在今天一篇备受争议的博客文章中,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突然告诉我子对象存在,尽管早些时候告诉我它没有!
我最初的反应是,这必须是一个错误,但经过进一步的考虑(并由ADO.NET团队支持),我意识到这种行为是由于实体框架在延迟加载Orders子查询时引起的. datacontext.
这是因为order是LINQ-To-Object查询:
var order = ( from o in alice.Orders where o.Item == "Item_Name" select o ).FirstOrDefault();
并且不会以任何方式访问datacontext,而他的foreach循环:
foreach( var order in data.Orders )
正在访问datacontext.
LINQ-To-SQL实际上为Orders创建了延迟加载的属性,因此当访问它们时,会执行另一个查询,LINQ to Entities会让您自行检索相关数据.
现在,我不是ORM的忠实粉丝,这正是原因所在.我发现为了让你想要的所有数据都在你的指尖,他们会反复执行你背后的查询,例如,上面的linq-to-sql查询可能会为每行客户运行一个额外的查询来获取订单.
然而,EF没有这样做似乎主要违反了最不惊讶的原则.虽然这是一种技术上正确的做事方式(您应该运行第二个查询来检索订单,或从视图中检索所有内容),但它的行为与您对ORM的预期不同.
那么,这是一个很好的框架设计吗?或者微软是否为我们考虑过这一点?
乔恩,
我也和实体一起玩过linq.在赶上linq to SQL之前还有很长的路要走.我必须使用linq实现每个类型继承表的实体.我最近发现一个很好的文章这也解释了整个1家公司2项不同ORM技术的东西在这里.
但是,您可以通过以下方式执行延迟加载:
// 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();
希望能帮助到你.
戴夫
那么,这是一个很好的框架设计吗?或者微软是否为我们考虑过这一点?
好吧,让我们分析一下 - 微软所做的所有想法,我们不必真正让我们变得懒散的程序员.但总的来说,它确实使我们更有成效(大多数情况下).所以,是他们在思维还是他们只是想给我们?