2013-02-22 36 views
2

我编码通过MS 101的LINQ例子,并且连接被投掷我回路;)LINQ的GroupInto选择

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 }); 

到第一个()的调用混淆我因为它不是在前面的查询表达式。

当我运行这个时,我得到一个错误,因为在它到达之前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 
             }); 

回答

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 
       ... 

GroupJoinJoin的好处是,可以Category有一个空Product的集合,它在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!对于这样一个无辜的小声明来说,这是一个非常重要的变化。我并没有把语法链接到流利的语法,但有时候“全面的”语法隐藏了真正发生的事情,这是产生错误的一个很好的方法。

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。这是一个伟大的工具,我发现自己经常使用它。

我同意他们对该样本的使用存在疑问。