【问题标题】:Entity Framework Code First 4.3 / LINQKit predicate for related tableEntity Framework Code First 4.3 / LINQKit 相关表谓词
【发布时间】:2023-03-30 06:23:01
【问题描述】:

我正在使用 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 对导航属性的了解,并且能够使用范围为导航属性类型的谓词,那就太好了。

【问题讨论】:

    标签: entity-framework entity-framework-4 linq-to-entities ef-code-first


    【解决方案1】:

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

    1. 定义一个谓词来查询您的内部属性 (subPredicate)
    2. Invoke 表示 subPredicate 来自另一个谓词 (predicate),针对父对象的属性。
    3. Expand 你的 predicate 在你的 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();
    

    【讨论】:

    • 感谢更新!您是否可以深入了解此谓词是否应用在服务器端,通过 LINQ/LINQKit 向 EF 提供可以转换为 SQL 的内容,还是在 EF 内部对未过滤的数据集应用蛮力?
    • @PittsburghDBA 这导致通过 EF 调用数据库,转换为 SQL。
    • @PittsburghDBA 没问题。您可以通过投票来感谢我。 ;)
    • @PittsburghDBA 我想我可以忍受。谢谢!
    【解决方案2】:

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

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

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

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

    不要和市政厅打架。

    【讨论】:

    • 我在这种情况下......经过大量阅读和反复试验和错误编码后,我也学会了不要与系统对抗,否则你会得到复杂而丑陋的代码。啊!!! EF 和 PredicateBuilder 对主要实体“有效”有好处。你最终对嵌套实体做了什么?我现在正处于十字路口,决定下一步该做什么。 (我知道你的回答已经 2 年了)。
    • 我们放弃了 EF,现在使用 SQLClient。这些 ORM 平台在原始性能方面都无法与 ADO.Net 竞争,更不用说这些谓词问题了。
    • @ThomasVeil 看看这里列出的残酷差异:web.archive.org/web/20131205132904/http://ormbattle.net
    • 同意,ADO.NET 无疑是山中之王。非常感谢,没有考虑这个。我现在要考虑的事情。可惜我花了这么多时间和精力在EF上。我现在问自己的问题是...... EF 生产是否在性能方面做好了准备。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多