1

我修改了 jbogards EntityFramework.Filters,它将对“全局过滤器”的支持添加到 EF DbContext。(见https://github.com/jbogard/EntityFramework.Filters

当我试图让它与一个简单的连接表达式一起工作时,我偶然发现了一个问题。

在我的场景中,我有一个“AccessPredicate”表,其中包含 IResource(文档或章节)的 id 和用户的 id。现在我想要实现的是过滤不允许用户看到的文档和章节

`modelBuilder.Conventions.Add(FilterConvention.Create<IResource, long>("UserId",
                (e, userId) => e.AccessPredicates.Any(@as => @as.UserId == userId)));`

为了支持这一点,我必须在 EntityFramework.Filters 中更改的是 ParameterReplacer.VisitLamda 方法,因为它试图始终返回 Func 类型的 lamda 表达式,但因为我有一个子 lamda (as.UserId == 2l)我必须添加一个类型检查:

`protected override Expression VisitLambda<T>(Expression<T> node)
    {
        var arg1 = typeof (T).GetGenericArguments().FirstOrDefault();
        if(arg1 != null && !arg1.IsAssignableFrom(typeof(TEntity)))
            return base.VisitLambda<T>(node);

        var body = Visit(node.Body);
        return Expression.Lambda<Func<TEntity, bool>>(body, node.Parameters[0]);
    }`

所以现在它在 FilterQueryVisitor.Visit(...) 的倒数第二行爆炸了

var output = result.Predicate.Accept(normalizer);

with the error: A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in EntityFramework.dll

Additional information: No property with the name 'AccessPredicates' is declared by the type 'CodeFirstDatabaseSchema.Document'.

AccessPredicates 是 Document 上的导航属性,但是 EdmType(我调试了引发错误的实体框架:System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.ValidateProperty)在其“成员”中只有两个项目集合:“Id”和“Title”

但是,如果我不使用过滤器,而是像这样手动编写查询: var x = ctx.Documents .Where(@d => @d.AccessPredicates.Any(@a => @a.UserId == userId)) .Take(1).FirstOrDefault(); 那么“成员”集合包含“Id”、“Title”、“AccessPredicates”和“Chapter”,正如我所期望的那样。你知道怎么可能吗?

在我看来,EntityFramework 为它解析的每个查询构造 StructuralTypes(继承 EdmType),当我添加过滤器时,我错过了一些东西......:/

为了便于调试,我添加了一个测试项目: http: //1drv.ms/1BbrBAL 只需在 package-manager 中运行“update-database”,然后按 F5。

我不知道这是否是一个真正的 EF 问题,但我不知道任何其他地方可以帮助我深入了解您所拥有的 EF 内部结构。我真的希望你能帮我解决这个问题:/

4

0 回答 0