【问题标题】:LINQ To Entities and Lazy LoadingLINQ To 实体和延迟加载
【发布时间】:2008-12-03 22:27:37
【问题描述】:

在今天的 controversial blog post 中,Hackification 对新的 LINQ To Entities 框架中似乎存在的错误发表了看法:

假设我搜索客户:

var alice = data.Customers.First( c => c.Name == "Alice" );

很好,效果很好。现在让我们看看 如果我能找到她的一份订单:

 var order = ( from o in alice.Orders
          where o.Item == "Item_Name"
          select o ).FirstOrDefault();

LINQ-to-SQL 将查找子行。 LINQ-to-Entities 将静默返回 什么都没有。

现在假设我遍历 数据库中的所有订单:

foreach( var order in data.Orders ) { 
Console.WriteLine( "Order: " + order.Item ); }

现在重复我的搜索:

var order = ( from o in alice.Orders
          where o.Item == "Item_Name"
          select o ).FirstOrDefault();

哇! LINQ-to-Entities 突然出现 告诉我子对象存在, 尽管早些时候告诉我它 没有!

我最初的反应是这一定是一个错误,但经过进一步考虑(和backed up by the ADO.NET Team),我意识到这种行为是由实体框架引起的,而不是在从数据上下文中拉出 Alice 时延迟加载 Orders 子查询.

这是因为 order 是一个 LINQ-To-Object 查询:

var order = ( from o in alice.Orders
      where o.Item == "Item_Name"
      select o ).FirstOrDefault();

并且没有以任何方式访问数据上下文,而他的 foreach 循环:

 foreach( var order in data.Orders )

正在访问数据上下文。

LINQ-To-SQL 实际上为 Orders 创建了延迟加载的属性,以便在访问时执行另一个查询,LINQ to Entities 让您手动检索相关数据。

现在,我不是 ORM 的忠实粉丝,这正是原因所在。我发现,为了让您想要的所有数据触手可及,他们会在您背后重复执行查询,例如,上面的 linq-to-sql 查询可能会为每行客户运行一个额外的查询以获取订单.

但是,EF 不这样做似乎在很大程度上违反了最小意外原则。虽然它在技术上是正确的做事方式(您应该运行第二个查询来检索订单,或从视图中检索所有内容),但它的行为与您对 ORM 的预期不同。

那么,这是好的框架设计吗?还是微软为我们考虑过这个问题?

【问题讨论】:

    标签: linq-to-sql linq-to-entities


    【解决方案1】:

    乔恩,

    我也一直在玩 linq to entity。在赶上 linq to SQL 之前还有很长的路要走。对于每个类型继承的表,我不得不使用 linq 到实体。我最近发现了一篇很好的文章,它解释了整个 1 公司 2 种不同 ORM 技术的事情here

    但是,您可以通过以下方式进行延迟加载:

    // Lazy Load Orders 
    var alice2 = data.Customers.First(c => c.Name == "Alice");
    
    // Should Load the Orders
    if (!alice2.Orders.IsLoaded)
        alice2.Orders.Load();
    

    或者您可以只在原始查询中包含订单:

    // Include Orders in original query
    var alice = data.Customers.Include("Orders").First(c => c.Name == "Alice");
    
    // Should already be loaded
    if (!alice.Orders.IsLoaded)
        alice.Orders.Load();
    

    希望对你有帮助。

    戴夫

    【讨论】:

    • 我同意,这篇博文并不完全知情。我相信他们应该花更多的时间来学习 L2E,然后再批评它——就好像他们在写这篇文章之前就决定不喜欢它,引起了巨大的骚动,因为他们不知道他们必须加载()...
    【解决方案2】:

    那么,这是好的框架设计吗?还是微软为我们考虑过这个问题?

    好吧,让我们分析一下——微软所做的所有想法,我们不必真的让我们成为更懒惰的程序员。但总的来说,它确实让我们更有效率(在大多数情况下)。那么他们在考虑还是他们只是在为我们考虑

    【讨论】:

      【解决方案3】:

      如果 LINQ-to-Sql 和 LINQ-to-Entities 来自两家不同的公司,这是可以接受的差异 - 没有法律规定所有 LINQ-To-Whatevers 必须以相同的方式实施。

      但是,他们都来自微软 - 我们不需要深入了解他们的内部开发团队和流程,就能知道如何使用表面上看起来完全一样的两种不同的东西.

      ORM 有自己的位置,确实填补了人们试图完成工作的空白,但 ORM 用户必须确切地知道他们的 ORM 是如何完成工作的 - 将其视为不可穿透的黑匣子只会给您带来麻烦。

      【讨论】:

        【解决方案4】:

        在这个问题上浪费了几天时间,我很同情。

        “错误”(如果有的话)是有一种合理的倾向,即期望抽象层会与这类问题隔离开来。从 LINQ 到实体,再到数据库层,更是如此。

        例如,如果不得不从 MS-SQL(使用 LingToSQL)切换到 MySQL(使用 LinqToEntities),人们会认为 LINQ 至少是相同的,如果不仅仅是为了节省重新编译的成本的话- 编写程序逻辑。

        不得不用 .Load() 和/或 LINQ 用 .Include() 乱扔代码,仅仅因为引擎盖下的持久性机制发生了变化,这似乎有点令人不安,尤其是在静默失败的情况下。 LINQ 层至少应该表现一致。

        许多 ORM 框架使用代理对象来透明地动态加载惰性对象,而不是仅仅返回 null,尽管我对集合未加载异常感到满意。

        我倾向于不接受他们故意为您的利益而做的借口;其他 ORM 框架让您可以根据需要注释您是想要预先加载还是延迟加载。在这里也可以这样做。

        【讨论】:

          【解决方案5】:

          我对 ORM 了解不多,但作为 LinqToSql 和 LinqToEntities 的用户,我希望当您尝试为 Alice 查询订单时,它会在您进行 linq 查询时为您执行额外的查询(而不是查询任何内容或查询每一行的所有内容)。

          期待似乎很自然

          from o in alice.Orders where o.Item == "Item_Name" select o
          

          考虑到这是人们首先使用 ORM 的原因之一(以简化数据访问)。

          我对 LinqToEntities 的了解越多,我就越认为 LinqToSql 能够充分满足大多数开发人员的需求。我通常只需要表格的一对一映射。

          【讨论】:

            【解决方案6】:

            尽管您不必了解 Microsoft 的内部开发团队和流程,但事实是这两种技术是两种完全不同的野兽。

            为简单起见,LINQ to SQL 的设计决策是隐式延迟加载集合。 ADO.NET Entity Framework 团队不想在用户不知情的情况下执行查询,因此他们将 API 设计为在第一个版本中显式加载。

            LINQ to SQL 已移交给 ADO.NET 团队,因此您可能会在未来看到 API 的整合,或者 LINQ to SQL 被折叠到实体框架中,或者您可能会看到 LINQ to SQL 因忽视而萎缩,最终被弃用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-03-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多