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

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

问题描述

今天有争议的博客文章,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:

假设我搜索一个客户:

Suppose I search for a customer:

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到实体突然 告诉我子对象存在, 尽管早先告诉过我 没有!

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

我最初的反应是这必须是一个错误,但经过进一步考虑(和

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.

这是因为订单是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 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查询可能会在每行Customer上运行一个附加查询以获取订单

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.

那么,这是一个好的框架设计吗?还是Microsoft为我们考虑了这个问题?

推荐答案

乔恩

我也一直在和linq一起玩实体游戏.在赶上linq to SQL之前,还有很长的路要走.我不得不对每个类型继承的表使用linq来实体.我最近找到了一篇很好的文章,该文章解释了整个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到实体和延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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