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

我正在尝试修改拦截的命令树,以向所有查询添加“IsActive = 1”过滤器。我已经注意到这类文件的严重不足。两个问题:

我如何选择性地拦截命令树,例如实现接口(interface)的实体(例如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());
        }
    }
}

这就是问题的症结所在。如您所见,我已经确定了一些需要包括的内容,但是我不知道如何将这些内容放在一起。
public class MyVisitor : BasicExpressionVisitor
{
    public override void Visit(DbFilterExpression expression)
    {
        // add WHERE [IsActive] = 1
        /* Building blocks:
         *      DbExpressionBuilder.Equal
         *      DbExpressionBuilder.True
         *      DbExpressionBuilder.And   --- only when a filter expression already exists
         */

        var isActiveProperty = expression.Property("IsActive");
        var equalExp = DbExpressionBuilder.Equal(isActiveProperty, DbExpressionBuilder.True);
    }
}

假设我们有这个:
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

但是我不知道从这里去哪里。

最佳答案

我使用以下引用信息来帮助实现自定义的“软删除”拦截机制:

  • Entity Framework: Building Applications with Entity Framework 6(据我所知,有关拦截器的部分大约在20分钟左右,重点是应回答您问题的SCAN节点)
  • How can I suppress execution from an Entity Framework 6 IDbCommandTreeInterceptor?
  • Missing EF Feature Workarounds: Filters(在注释中有关于查询缓存问题的有趣观点)

  • 希望这会有所帮助

    关于c# - 学习 Entity Framework 6命令树拦截器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29377494/

    10-14 03:20