【问题标题】:How can I make this SelectMany use a Join?我怎样才能让这个 SelectMany 使用加入?
【发布时间】:2011-07-08 06:23:29
【问题描述】:

鉴于我在 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,虽然我看不到第一个查询的变化,但不确定这是否表明我的查询存在问题。

【问题讨论】:

  • 一个订单可以有多个客户?还是那些箭头不重要?
  • 一单一客。对不起,我改变了它,希望能更好地传达意思。

标签: c# linq-to-sql


【解决方案1】:

我认为这里的关键是

customer.CustomerOrders

这是一个 EntitySet,而不是 IQueryable,因此您的第一个查询不会直接转换为 SQL 查询。相反,它被解释为多个查询,每个订单一个。

无论如何,这是我的猜测。

【讨论】:

  • 谢谢弗朗西斯科,现在说得通了。尽管这并不能直接回答问题,但它确实为我指明了正确的方向。我将添加我自己的答案,我觉得让我自己的答案正确是不对的。
【解决方案2】:

这个怎么样:

Customers.First().CustomerOrders.SelectMany(item => item.OrderLines)

【讨论】:

  • 产生了相同的 n+1 个查询。我正在通过 LinqPad 运行这些以查看结果。
【解决方案3】:

我不是 100% 确定。但我的猜测是,与第二个解决方案相比,您实际上是通过一个值将两个集合连接起来,而您正在遍历查询构建方式的关系。

【讨论】:

  • 但是不应该遍历关系告诉 L2S 无论如何都要使用 Join 吗?因为它知道两个表之间的连接。
  • 当然它可能会告诉L2S有关连接的信息,但这就是L2S的实现方式。我的猜测是实现更清洁,更容易扩展它现在的方式,但我明白你的意思。
【解决方案4】:

因此,在弗朗西斯科的回答和对 LINQPad 的试验之后,我想出了一个不错的解决方法。

var lines = from c in Customers
            where c == customer
            from o in c.CustomerOrders
            from l in o.OrderLines
            select l;

这会强制 EntitySet 成为一个表达式,然后提供者将其转换为适当的查询。前两行是关键,通过查询 IQueryable 和 then 将 EntitySet 放入 SelectMany 中,它变成了一个表达式。这也适用于其他运算符,如 Where、Select 等。

【讨论】:

    【解决方案5】:

    试试这个查询:

    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,它演示了在查询表达式中的行为与实际调用时不同的方法。

    【讨论】:

    • 这会产生相同的 n+1 个查询。有趣的是,该查询不返回 IQueryable,而是返回 IEnumerable。一定是因为 EntitySet.
    猜你喜欢
    • 1970-01-01
    • 2019-06-13
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多