鉴于我在Linq To Sql模型中有三个表(Customer,Orders和OrderLines)
客户 - 一对多 - >订单 - 一对多 - > OrderLines
当我使用
时var customer = Customers.First();
var manyWay = from o in customer.CustomerOrders
from l in o.OrderLines
select l;
我看到一个查询获得客户,这是有道理的。然后我看到客户订单的查询,然后是每个订单获得订单行的单个查询,而不是加入两个订单。共有n + 1个查询(不计入客户)
但如果我使用
var tableWay = from o in Orders
from l in OrderLines
where o.Customer == customer
&& l.Order == o
select l;
然后,我没有看到每个订单获得订单行的单个查询,而是看到连接两个表的单个查询。总共1个查询(不计入客户)
我更喜欢使用第一个Linq查询,因为它对我来说似乎更具可读性,但为什么L2S不像我在第一个查询中所期望的那样加入表?使用LINQPad我看到第二个查询被编译成SelectMany,虽然我没有看到第一个查询的变化,不确定这是否是我查询中某些问题的指示。
答案 0 :(得分:2)
我认为这里的关键是
customer.CustomerOrders
这是一个EntitySet,而不是IQueryable,因此您的第一个查询不会直接转换为SQL查询。相反,它被解释为许多查询,每个订单一个。
无论如何,这是我的猜测。
答案 1 :(得分:1)
这个怎么样:
Customers.First().CustomerOrders.SelectMany(item => item.OrderLines)
答案 2 :(得分:1)
我不是百分百肯定。但我的猜测是因为你正在遍历建立查询的关系,与第二个解决方案相比,你实际上是通过一个值加入两个集合。
答案 3 :(得分:1)
尝试此查询:
IQueryable<OrderLine> query =
from c in myDataContext.customers.Take(1)
from o in c.CustomerOrders
from l in o.OrderLines
select l;
您可以转到CustomerOrders属性定义,查看属性在与实际实例一起使用时的行为方式。当在查询表达式中使用该属性时,行为取决于查询提供者 - 在这种情况下通常不会运行属性代码。
另请参阅this answer,它演示了一种在查询表达式中行为不同的方法,而不是实际调用它的方法。
答案 4 :(得分:1)
因此,经过Francisco的回答并尝试使用LINQPad,我得到了一个不错的解决方法。
var lines = from c in Customers
where c == customer
from o in c.CustomerOrders
from l in o.OrderLines
select l;
这会强制EntitySet成为一个表达式,然后提供程序将转换为适当的查询。前两行是关键,通过查询IQueryable和然后将EntitySet放入SelectMany它变成一个表达式。这适用于其他运营商,Where,Select等