5

我正在使用 Entity Framework 4.3.1 和 Code First 方法。另外,我正在使用 LinqKit 来使用 PredicateBuilder。

如果我有这样的表:

位置、时区(多:1)

..我希望有这样的东西:

Expression<Func<TimeZone, bool>> pred = PredicateBuilder.True<TimeZone>();
pred = pred.And(tz => tz.TimeZoneCode == "EST");

List<Location> locations = context.Locations
    .AsExpandable().Where(pred)
    .Select(loc => loc).ToList();

这不起作用,因为谓词是为接受 TimeZone 而构建的,但 Where() 方法接收的是 Location。

我可以像这样重写谓词,但我不想这样做,因为我想要一个为特定类型创建谓词的谓词工厂(我不想以这种方式使用 Navigator 属性):

Expression<Func<Location, bool>> pred = PredicateBuilder.True<Location>();
pred = pred.And(loc => loc.TimeZone.TimeZoneCode == "EST");

我可以使用什么语法(如果有的话)来使用第一个示例中构造的谓词,它需要一个 TimeZone,而不是让它接受一个 Location 并通过导航属性遍历树(因为这不太可重用)。如果有一种方法可以首先利用 EF 对导航属性的了解,并且能够使用范围为导航属性类型的谓词,那就太好了。

4

2 回答 2

6

经过大约一周的努力,我发现你实际上可以做到这一点。步骤是:

  1. 定义一个 Predicate 来查询你的内部属性 ( subPredicate)
  2. InvokesubPredicate另一个 Predicate ( predicate) 中,针对父对象的属性。
  3. Expandpredicate在你的Where条款中使用它时。

这是您的示例的修改后的代码:

var subPredicate = PredicateBuilder.True<TimeZone>();
subPredicate = subPredicate.And(tz => tz.TimeZoneCode == "EST");

var predicate = PredicateBuilder.True<Location>();
predicate = predicate.And(l => subPredicate.Invoke(l.TimeZone));

List<Location> locations = context.Locations
    .AsExpandable().Where(pred.Expand())
    .Select(loc => loc).ToList();
于 2015-01-27T15:02:26.810 回答
2

只是为了更新这一点:事实证明,这些谓词的目的是过滤主要实体。心理概念是:决定你想归还哪些实体,然后归还它们。EF 显然不是为这种在子实体上的深度谓词应用程序而设计的。

一个人(我不记得在哪里)提出了一个很好的观点:如果孩子们是预先加载的,你就不会期望一个部分加载的集合。因此,例如,拥有一个 Invoice 实体,但只有一半的 Invoice Lines 是没有意义的。

我想要实现的更像是 EXISTS() 或 IN(),您可以在其中说“给我所有发票,其中有产品类型‘螺母’和‘螺栓’的发票行”。这是可行的,但您可能必须应用 LINQ 或编写自己的对象。EF 开箱即用的目的是将发票交给您,然后您可以懒惰或急切地加载发票行,但不直接将它们用作数据库中的过滤器。

我看到有一些结构可以完成一些接近的事情,但是语法很快变得非常难以管理。

不要和市政厅打架。

于 2012-09-26T14:53:37.653 回答