在Entity Framework Core中,您可以覆盖SaveChanges
中的SaveChangesAsync
/ DbContext
方法,并基于不同的状态,例如:EntityState.Added
或EntityState.Modified
或{ {1}},您可以创建一些关于何时创建,修改或删除某些记录的审核解决方案。您可以在操作之前和之后保存实体的状态。这里的一切都很完美!
我们可以为读取/查询/选择/查看操作做类似的事情吗?
答案 0 :(得分:2)
我挖了一点,发现IQueryable
的实际执行是由EntityQueryProvider : IAsyncQueryProvider, IQueryProvider
完成的。
所以......你覆盖默认的EntityQueryProvider
来进行记录:
public class LoggingQueryProvider : EntityQueryProvider
{
public LoggingQueryProvider(IQueryCompiler queryCompiler) : base(queryCompiler) { }
public override object Execute(Expression expression)
{
var result = base.Execute(expression);
//log
return result;
}
public override TResult Execute<TResult>(Expression expression)
{
var result = base.Execute<TResult>(expression);
//log
return result;
}
public override IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
var result = base.ExecuteAsync<TResult>(expression);
//log
return result;
}
public override Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
var result = base.ExecuteAsync<TResult>(expression, cancellationToken);
//log
return result;
}
}
并在StartUp.ConfigureServices(IServiceCollection services)
services.AddDbContext<XPContext>(builder =>
builder
.UseSqlServer(Configuration["TryDBConnectionString"])
.ReplaceService<IAsyncQueryProvider, LoggingQueryProvider>()
);
这不是很直接,但你应该能够从表达式中获取一些信息,比如实体类型,你显然可以访问实际结果。对于异步方法,事情看起来有点复杂,但是......
答案 1 :(得分:0)
大多数策略都依赖于覆盖SaveChanges()
来审核数据,但您也可以通过覆盖Dispose()
方法来访问其他数据。
当从数据库中查询数据时,它会被添加到dbContext中,如果它被读取但未被更改,则应该有EntityState.Unchanged
。
假设每个请求的新实例的典型Web应用程序样式DbContext
范围,那么按id查询将意味着ChangeTracker
中有一个条目,DbContext
具有该状态处置。
您可以尝试这样的事情:
public override void Dispose()
{
var unchanged = ChangeTracker.Entries()
.Where(x => x.EntityState == EntityState.Unchanged);
// log your unchanged entries here
base.Dispose();
}
这并非完全万无一失,因为您可能会在创建/更新过程中从某些表中检索数据作为验证的一部分,或者您可能在多个存储库之间共享上下文,因此您需要考虑哪些实体需要仔细审核以及访问哪些内容你使用的模式
答案 2 :(得分:0)
我建议在更高级别登录。例如,如果您正在使用WebApi,则可以登录OWIN管道级别,从而记录信息请求。
记录下限结束了第二次猜测并重新遍历丑陋的数据并最终导致效率低下。