是否可以拦截READ操作?

时间:2017-10-21 20:12:39

标签: c# entity-framework-core

在Entity Framework Core中,您可以覆盖SaveChanges中的SaveChangesAsync / DbContext方法,并基于不同的状态,例如:EntityState.AddedEntityState.Modified或{ {1}},您可以创建一些关于何时创建,修改或删除某些记录的审核解决方案。您可以在操作之前和之后保存实体的状态。这里的一切都很完美!

我们可以为读取/查询/选择/查看操作做类似的事情吗?

3 个答案:

答案 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)

中配置DbContext时注册
    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管道级别,从而记录信息请求。
记录下限结束了第二次猜测并重新遍历丑陋的数据并最终导致效率低下。