在嵌套实体列表上使用谓词时的意外行为
本文关键字:意外 谓词 实体 嵌套 列表 | 更新日期: 2023-09-27 18:06:40
我偶然发现了一个我无法解释的谜题,也许这里有人能解释。下面是一个(相当长但完整的)代码片段:
public class Foo
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Foo> InnerFoo { get; set; }
}
public class AppContext : DbContext
{
public IDbSet<Foo> Foos { get; set; }
}
public class Initializer : DropCreateDatabaseAlways<AppContext>
{
protected override void Seed(AppContext context)
{
var list = new List<Foo>
{
new Foo {Name = "one", InnerFoo = new List<Foo>{new Foo {Name = "Four"}}},
new Foo {Name = "two"},
new Foo {Name = "three"},
};
list.ForEach(f => context.Foos.Add(f));
}
}
public class Filter
{
public static Expression<Func<Foo, bool>> GetPredicate()
{
return p => p.Name != null && p.Name.Length > 3;
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new Initializer());
using (var ctx = new AppContext())
{
var predicate = Filter.GetPredicate();
var list = ctx.Foos.Where(f => f.InnerFoo.AsQueryable().Where(predicate).Count() > 0).ToList(); // this works
// var list = ctx.Foos.Where(f => f.InnerFoo.AsQueryable().Where(Filter.GetPredicate()).Count() > 0).ToList(); // this doesn't
foreach (var s in list)
{
Console.WriteLine(s.Name);
}
}
}
}
被注释掉的那行不能工作——在运行时抛出一个异常——"内部。net框架数据提供程序错误1025."我正在使用EntityFramework.4.1.10715.0
谁能告诉我为什么?
附带问题:我正在寻找一种方法来保持在几个不同的类中使用的过滤表达式。
问题是您的内部Where
已经在ctx.Foos
上的"外部Where
"的上下文中-因此对Filter.GetPredicate()
的调用最终作为表达式树的一部分,并且实体框架不知道它意味着什么或如何将其翻译成SQL。
这就是为什么会发生…我不确定现在最好的解决方案,除非你可以提取谓词到一个单独的变量,你需要它。
(顺便说一句,使用Any(...)
通常比使用...Count() > 0
更有表现力——在LINQ to Objects中,它可以产生巨大的差异。)
你自己已经暗示了这一点,但只是为了让未来的读者清楚。您可以像前面那样使用函数来生成谓词,但是需要将表达式存储在函数中的一个中间表达式中。
。变化:
var list = ctx.Foos.Where(f => f.InnerFoo.AsQueryable().Where(Filter.GetPredicate()).Count() > 0).ToList();
为:
var pred = Filter.GetPredicate();
var list = ctx.Foos.Where(f => f.InnerFoo.AsQueryable().Where(pred).Count() > 0).ToList();
我还是不明白为什么会这样。