【发布时间】: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