LINQ To 实体和延迟加载 [英] LINQ To Entities and Lazy Loading

查看:21
本文介绍了LINQ To 实体和延迟加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天有争议的博文,Hackification 对新 LINQ To Entities 框架中似乎存在的错误进行了辩护:

In a controversial blog post today, Hackification pontificates on what appears to be a bug in the new LINQ To Entities framework:

假设我搜索客户:

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

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

Fine, that works nicely. Now let’s see if I can find one of her orders:

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

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

LINQ-to-SQL will find the child row. LINQ-to-Entities will silently return nothing.

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

Now let’s suppose I iterate through all orders in the database:

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 突然出现告诉我子对象存在,尽管早先告诉我它没有!

Wow! LINQ-to-Entities is suddenly telling me the child object exists, despite telling me earlier that it didn’t!

我最初的反应是这一定是一个错误,但经过进一步考虑(和 由 ADO.NET 团队支持),我意识到这种行为是由实体框架在从数据上下文中拉出 Alice 时没有延迟加载 Orders 子查询造成的.

My initial reaction was that this had to be a bug, but after further consideration (and backed up by the ADO.NET Team), I realized that this behavior was caused by the Entity Framework not lazy loading the Orders subquery when Alice is pulled from the datacontext.

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

This is because order is a LINQ-To-Object query:

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

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

And is not accessing the datacontext in any way, while his foreach loop:

 foreach( var order in data.Orders )

正在访问数据上下文.

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

LINQ-To-SQL actually created lazy loaded properties for Orders, so that when accessed, would perform another query, LINQ to Entities leaves it up to you to manually retrieve related data.

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

Now, I'm not a big fan of ORM's, and this is precisly the reason. I've found that in order to have all the data you want ready at your fingertips, they repeatedly execute queries behind your back, for example, that linq-to-sql query above might run an additional query per row of Customers to get Orders.

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

However, the EF not doing this seems to majorly violate the principle of least surprise. While it is a technically correct way to do things (You should run a second query to retrieve orders, or retrieve everything from a view), it does not behave like you would expect from an ORM.

那么,这样的框架设计好吗?还是微软为我们考虑的太多了?

推荐答案

Jon,

我也一直在玩 linq to entity.在赶上 linq to SQL 之前还有很长的路要走.我不得不将 linq to entity 用于每个类型继承的表格.我最近找到了一篇很好的文章,它解释了整个 1 家公司 2 种不同的 ORM 技术这里.

I've been playing with linq to entities also. It's got a long way to go before it catches up with linq to SQL. I've had to use linq to entities for the Table per Type Inheritance stuff. I found a good article recently which explains the whole 1 company 2 different ORM technologies thing here.

但是,在某种程度上,您可以通过以下方式进行延迟加载:

However you can do lazy loading, in a way, by doing this:

// Lazy Load Orders 
var alice2 = data.Customers.First(c => c.Name == "Alice");

// Should Load the Orders
if (!alice2.Orders.IsLoaded)
    alice2.Orders.Load();

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

or you could just include the Orders in the original query:

// 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();

希望有帮助.

戴夫

这篇关于LINQ To 实体和延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆