我的初步反应是这一定是个bug,但经过进一步考虑(并得到ADO.NET团队的支持),我意识到这种行为是由实体框架在从数据上下文中获取Alice时未进行订单子查询的惰性加载导致的。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 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 ); }
And now repeat my search:
var order = ( from o in alice.Orders where o.Item == "Item_Name" select o ).FirstOrDefault();
Wow! LINQ-to-Entities is suddenly telling me the child object exists, despite telling me earlier that it didn’t!
这是因为订单是一个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那样表现出人们的预期。
那么,这是好的框架设计吗?还是微软正在为我们过度思考?