C# 学习实体框架6命令树拦截器

C# 学习实体框架6命令树拦截器,c#,entity-framework,entity-framework-6,interceptor,C#,Entity Framework,Entity Framework 6,Interceptor,这纯粹是一个学习实验(耶,科学!)。这并不意味着要在任何地方实际使用。我想了解EF6的命令树拦截器是如何工作的 我正试图修改截获的命令树,以便在所有查询中添加一个“IsActive=1”过滤器。我注意到在这类事情的文档中有一个严重的缺陷。两个问题: 如何有选择地截取实现接口的实体的命令树(例如,IHasAnActiveProperty)?现在我注意到拦截器正在拦截历史上下文的查询,这与MyEntity无关 如何将筛选器添加到所有查询 public class MyEntity { [Da

这纯粹是一个学习实验(耶,科学!)。这并不意味着要在任何地方实际使用。我想了解EF6的命令树拦截器是如何工作的

我正试图修改截获的命令树,以便在所有查询中添加一个“IsActive=1”过滤器。我注意到在这类事情的文档中有一个严重的缺陷。两个问题:

如何有选择地截取实现接口的实体的命令树(例如,
IHasAnActiveProperty
)?现在我注意到拦截器正在拦截历史上下文的查询,这与MyEntity无关

如何将筛选器添加到所有查询

public class MyEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }
}

public class MyDbContext : DbContext
{
    public DbSet<MyEntity> Entities { get; set; }

    public MyDbContext() : base("default") { }


    public MyDbContext(string nameOrConnectionString)
        : base(nameOrConnectionString) {}
}

public class MyConfiguration : DbConfiguration
{
    public MyConfiguration()
    {
        AddInterceptor(new MyInterceptor());
    }
}

public class MyInterceptor : IDbCommandTreeInterceptor
{
    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
    {
        var query = interceptionContext.Result as DbQueryCommandTree;
        if (query != null)
        {
            Debug.WriteLine("##################");
            Debug.WriteLine("DataSpace: {0}", interceptionContext.Result.DataSpace);
            Debug.WriteLine(query.ToString());

            query.Query.Accept(new MyVisitor());
        }
    }
}
假设我们有这样的情况:

class Program
{
    static void Main(string[] args)
    {
        using (var ctx = new MyDbContext())
        {
            var entities = ctx.Entities.FirstOrDefault(x => x.Name == "amy");
            Console.WriteLine(entities);
        }
    }
}
此查询将生成此命令树:

DbQueryCommandTree
|_Parameters
|_Query : Collection{Record['Id'=Edm.Int32, 'Name'=Edm.String, 'IsActive'=Edm.Boolean]}
  |_Project
    |_Input : 'Limit1'
    | |_Limit
    |   |_Filter
    |   | |_Input : 'Extent1'
    |   | | |_Scan : CodeFirstDatabase.MyEntity
    |   | |_Predicate
    |   |   |_
    |   |     |_'amy'
    |   |     |_=
    |   |     |_Var(Extent1).Name
    |   |_1
    |_Projection
      |_NewInstance : Record['Id'=Edm.Int32, 'Name'=Edm.String, 'IsActive'=Edm.Boolean]
        |_Column : 'Id'
        | |_Var(Limit1).Id
        |_Column : 'Name'
        | |_Var(Limit1).Name
        |_Column : 'IsActive'
          |_Var(Limit1).IsActive

但我不知道从这里该怎么办。

我使用了以下参考资料来帮助我实现自定义的“软删除”拦截机制:

  • (据我记忆所及,关于拦截器的部分大约在20分钟左右,重点是
    扫描
    节点,它应该回答您的问题)
  • (注释中有一个关于查询缓存问题的有趣观点)

希望这会有所帮助

ExpressionVisitor的设计目的不是修改表达式,而是了解它的存在和/或记录它。如果你想修改命令,你必须从
IDbCommandInterceptor
@ErikPhilips中删除,这就解释了这么多。@Amy那么你有没有得到过代码的工作版本?我有兴趣从中学习。
DbQueryCommandTree
|_Parameters
|_Query : Collection{Record['Id'=Edm.Int32, 'Name'=Edm.String, 'IsActive'=Edm.Boolean]}
  |_Project
    |_Input : 'Limit1'
    | |_Limit
    |   |_Filter
    |   | |_Input : 'Extent1'
    |   | | |_Scan : CodeFirstDatabase.MyEntity
    |   | |_Predicate
    |   |   |_
    |   |     |_'amy'
    |   |     |_=
    |   |     |_Var(Extent1).Name
    |   |_1
    |_Projection
      |_NewInstance : Record['Id'=Edm.Int32, 'Name'=Edm.String, 'IsActive'=Edm.Boolean]
        |_Column : 'Id'
        | |_Var(Limit1).Id
        |_Column : 'Name'
        | |_Var(Limit1).Name
        |_Column : 'IsActive'
          |_Var(Limit1).IsActive