2

我正在通过 MS 101 Linq 示例进行编码,连接让我陷入了循环;)

示例104旨在展示稍微复杂的组连接是如何工作的:

var prodByCategory =
    from cat in categories
    join prod in products on cat equals prod.Category into ps
    from p in ps    // <-- ?
    select new { Category = cat, p.ProductName };

带“?”的部分 让我感到困惑,因为它看起来 p 与 ps 完全相同,并且该子句不在前面的示例中。

所以我尝试使用方法/linq 语法来编写它,我放在一起看起来像这样:

var prodByCategory = categories.GroupJoin(products, c => c, p => p.Category, (c, p) => new { Category = c, p.First().ProductName });

对 First() 的调用让我感到困惑,因为它不在前面的查询表达式中。

当我运行它时,我得到一个错误,因为 p 在它到达第一个之前是空的。我不确定这怎么可能,因为类别列表肯定与产品集合中的类别匹配。

foreach (var item in prodByCategory)
{
    Console.WriteLine(item.ProductName + ": " + item.Category);
}

产品已经有一个类别字段。那么查询有什么好处呢?我想这只是一个学习的东西,但我无法理解这里的价值(尽管这可能是因为我不明白这两个集合是如何相关的)。


更新:

玩弄了格特的建议。请参阅下面他清晰的解释。经过轻微的清理后,这有效:

        var prodByCategory = categories.GroupJoin(products, cat => cat, prod => prod.Category,
              (cat, prod) => new { cat, products })
           .SelectMany(x => x.products
                          , (x, p) =>
                                      new
                                      {
                                          Category = x.cat,    // x.cat.CategoryName not accessible here
                                          ProductName = p.ProductName
                                      });
4

2 回答 2

1

你是对的,它看起来毫无用处。GroupJoin(或join- into)用于执行加入和分组的混合。连接右侧的项目被分组在左侧的项目中。所以,这个查询在综合语法中

from cat in Categories
join prod in Products on cat equals prod.Category into products
select new { Category = cat.CategoryName, 
             Products = products.Select (p => p.ProductName) }

以其流畅的语法等价

Categories.GroupJoin(Products, cat => cat, prod => prod.Category, 
    (cat, products => new  
                 {
                    Category = cat.CategoryName, 
                    Products = products.Select (p => p.ProductName)
                 })

结果是

Beverages       Chai
                Chang
                Guaraná Fantástica
                Sasquatch Ale
                ...
Condiments      Aniseed Syrup
                Chef Anton's Cajun Seasoning
                Chef Anton's Gumbo Mix
                Grandma's Boysenberry Spread
                ...

GroupJoinvs.的好处Join是 aCategory可以有一个空的Products 集合,这在 SQL 中类似于外连接。


join-into其次的效果from是分组结构再次展平。所以

from cat in Categories
join prod in Products on cat equals prod.Category into ps
from p in ps
select new { Category = cat.CategoryName, p.ProductName }

与其等价物

Categories.GroupJoin(Products, cat => cat, prod => prod.Category, 
      (cat, products) => new {cat, products})
   .SelectMany(x => x.products
                  , (x, p) => 
                              new  
                              {
                                  Category = x.cat.CategoryName, 
                                  ProductName = p.ProductName
                              })

生产

Category        ProductName
--------------- ----------------------------------------
Beverages       Chai
Beverages       Chang
Condiments      Aniseed Syrup
Condiments      Chef Anton's Cajun Seasoning
Condiments      Chef Anton's Gumbo Mix
Condiments      Grandma's Boysenberry Spread
Produce         Uncle Bob's Organic Dried Pears
Condiments      Northwoods Cranberry Sauce
Meat/Poultry    Mishi Kobe Niku
...

这与使用简单的连接开始相同。

所以这部分from p in ps看起来不应该从本质上改变查询。不过是伪装的SelectMany!对于这样一个天真的小声明来说,这是一个相当重要的变化。我不拘泥于流利的语法,但有时“全面”的语法会隐藏真正发生的事情,这是产生错误的好方法。

于 2013-02-22T21:04:57.197 回答
1

我相信你翻译成流利的语法是不正确的。它应该是:

var prodByCategory = categories.GroupJoin(products, c => c, p => p.Category, (c, p) => new  { c = c, p = p })
                         .SelectMany (ps => ps.p, (ps, p) => new  { Category = ps.c, ProductName = p.ProductName });

我建议使用LinqPad来检查 LINQ 语句的流畅语法翻译和生成的 SQL。这是一个很棒的工具,我发现自己经常使用它。

我同意他们对该样本的使用是有问题的。

于 2013-02-22T19:58:01.393 回答