如何让SelectMany使用Join?

时间:2011-07-06 20:59:23

标签: c# linq-to-sql

鉴于我在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,虽然我没有看到第一个查询的变化,不确定这是否是我查询中某些问题的指示。

5 个答案:

答案 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等