是否可以拦截READ操作?

问题描述:

在实体框架的核心,您可以覆盖DbContextSaveChanges/SaveChangesAsync方法和基于像不同的状态:EntityState.AddedEntityState.ModifiedEntityState.Deleted,您可以创建什么时候和谁创建,修改或删除某些记录一些审计解决方案。您可以在操作前后保存实体的状态。这里所有的好东西都很完美是否可以拦截READ操作?

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

+0

为什么这应该关闭?这个问题有什么问题? – user2818430

+0

看看如果https://stackoverflow.com/questions/45132553/objectstatemanager-objectstatemanagerchanged-in-entity-framework-core/45192985#45192985可以帮助 –

+0

由此你的意思是如何记录SELECT语句或不同的东西? – Evk

我挖了一点,发现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>() 
    ); 

配置的DbContext当你注册它这不是很简单的,但你应该能够从表达式中获得一些信息,如实体类型,并且您显然可以访问实际结果。异步方法看起来有点复杂,但...

+0

我喜欢扩展查询提供者的想法,但你打算如何在没有dbContext的情况下登录到数据库? –

+0

想到使用单独的'DbContext' ... –

大多数策略都依赖于覆盖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(); 
} 

这不完全万无一失,因为你可能会在一个创建/更新过程中检索某些表数据作为验证的一部分,或者你可能跨越共用同一个上下文多个存储库,因此您需要考虑哪些实体需要仔细审核以及使用哪种访问模式

+0

如何查询'AsNoTracking()'? –

+0

@GertArnold正如我所说 - 不是万无一失。假设OP可以控制所有查询。现在你提到它'AsNoChangeTracking()'可以添加一个从审计中排除某些查询的细粒度方法。 –

我建议您在更高级别进行日志记录。例如,如果您使用的是WebApi,则可以在OWIN管道级别登录,从而记录信息请求。
通过记录低端数据来进行第二次猜测,并重新读取丑陋的数据,并最终导致效率低下。