【问题标题】:C# linq left out join does not work using DefaultIfEmptyC# linq left out join 不能使用 DefaultIfEmpty
【发布时间】:2014-08-25 05:33:41
【问题描述】:

我是 C# 新手,我有一个关于在 LINQ 中使用左连接的查询。

我有两个数据源 - 一个是类别集合,一个是产品集合。我想将这两个数据源连接在一起,这样我就可以得到这样的结果:

Category Name (Fruit) - Product Name ( peach)- Source ( QLD,NSW).

请注意,我在 products 集合中将 Source 作为 List 集合。

我这里有两个问题:

  1. 当我使用 DefaultIfEmpty 时,如果 Source 集合不存在,我无法设置对 null Source 集合的正确引用 - 但是,如果产品名称不存在,我可以引用有意义的字符串说“不存在”。如果左连接找不到产品的来源,任何人都可以帮助展示如何放置一个空字符串?
  2. 我找不到输出 Category Name 的方法 - 就像最终结果中的 Fruit ,Vegetables 虽然我可以在 group join 中输出,但知道该怎么做吗?

我在这里附上了我的代码。

class Product
{
    public string Name { get; set; }
    public int CategoryID { get; set; }
    public List<string> Source;
}

class Category
{
    public string Name { get; set; }
    public int ID { get; set; }
}
// Specify the first data source.
List<Category> categories = new List<Category>()
{ 
    new Category(){Name="Beverages", ID=001},
    new Category(){ Name="Condiments", ID=002},
    new Category(){ Name="Vegetables", ID=003},
    new Category() {  Name="Grains", ID=004},
    new Category() {  Name="Fruit", ID=005}            
};

// Specify the second data source.
List<Product> products = new List<Product>()
{
     new Product{Name="Cola",CategoryID=001,  Source = new List<string> {"NSW","VIC","QLD"} },  
     new Product{Name="Mustard", CategoryID=002 ,  Source = new List<string> {"NSW","VIC","SA"} },
     new Product{Name="Pickles", CategoryID=002 ,  Source = new List<string> {"NSW","VIC","NT"} },
     new Product{Name="Carrots", CategoryID=003 ,  Source = new List<string> {"NSW","VIC","TAS"} },
     new Product{Name="Bok Choy", CategoryID=003 ,  Source = new List<string> {"NSW","VIC","ACT"} },
     new Product{Name="Eggplant", CategoryID=003 ,  Source = new List<string> {"QLD","NSW"} },
     new Product{Name="Broccoli", CategoryID=003 ,  Source = new List<string> {"QLD,SA"} },
     new Product{Name="Peaches", CategoryID=005 ,  Source = new List<string> {"NSW","VIC","NZ"} },
     new Product{Name="Melons", CategoryID=005,  Source = new List<string> {"NSW","VIC"} },
};

以下代码不适用于 LINQ 中的 left join

void LeftOuterJoin()
{
   var leftOuterQuery =
       from category in categories
       join prod in products on category.ID equals prod.CategoryID into prodGroup          
       select prodGroup.DefaultIfEmpty(new Product()
       { Name = "Nothing!", CategoryID = category.ID})
       ;

    // Store the count of total items (for demonstration only). 
    int totalItems = 0;

    Console.WriteLine("Left Outer Join:");

    // A nested foreach statement  is required to access group items 
    foreach (var prodGrouping in leftOuterQuery)
    {
        Console.WriteLine("\nGroup count: {0}", prodGrouping.Count());

        // Intellisense does not show category name  if I use prodGrouping.Name 
         //and want to get categorhy name since left join produce hierarchy data 
         //why category name is not showing up - I am itinerate from 1st loop ??
        foreach (var item in prodGrouping)
        {
            totalItems++;
            Console.WriteLine("  {0,-10}{1}", item.Name, item.CategoryID);

            foreach (var s in item.Source)
            {
                Console.WriteLine("Souce state: {0}", s.ToString());
            }
        }
    }

    Console.WriteLine(System.Environment.NewLine);
}

嗨,Marcin,我更改了原来的代码,但它给了我重复的记录,你知道为什么吗?

 void LeftOuterJoin()
    {
        // Create the query. 
        var leftOuterQuery =
           from category in categories
           join prod in products on category.ID equals prod.CategoryID into prodGroup
           from prodG in prodGroup.DefaultIfEmpty()       
            select new
            {
                Category = category.Name,
                //Products = products.OrderBy(x => x.Name)
                Products = from prod2 in prodGroup
                           orderby prod2.Name
                           select prod2
            };


        Console.WriteLine("Left Outer Join:");

        // A nested foreach statement  is required to access group items 
        foreach (var item in leftOuterQuery)
        {                 

             Console.WriteLine("  {0,-10}", item.Category);
             foreach ( var p in item.Products)
             {
                 Console.WriteLine("ProductName: {0}", p.Name);
                 foreach (var s in p.Source)
                 {
                     Console.WriteLine("SourceName: {0}", s.ToString());

                 }
             }                   


        }

    }

我想得到这样的结果:

  Group Beverages:1
  Cola      1
  Souce state: NSW
  Souce state: VIC
  Souce state: QLD

 Group : Condiments
  Mustard   2
   Souce state: NSW
   Souce state: VIC
   Souce state: SA
 Pickles   2
  Souce state: NSW
  Souce state: VIC
  Souce state: NT

但是我得到了这样的结果:

Beverages
 ProductName: Cola
 SourceName: NSW
 SourceName: VIC
 SourceName: QLD

Condiments
 ProductName: Mustard
 SourceName: NSW
 SourceName: VIC
 SourceName: SA    
 ProductName: Pickle
 SourceName: NSW
 SourceName: VIC
 SourceName: NT

Condiments
 ProductName: Mustard
 SourceName: NSW
 SourceName: VIC
 SourceName: SA
 ProductName: Pickle
 SourceName: NSW
 SourceName: VIC
 SourceName: NT

【问题讨论】:

  • 可能你需要使用from pg in prodGroup.DefaultIfEmpty(..) select pg而不是select prodGroup.DefaultIfEmpty(...)
  • 如果我使用 from pg in prodGroup.DefaultIfEmpty(..) select pg ...它不会给我类别信息..我会得到扁平化数据...艾伦
  • 这是我想看到的结果:
  • 结果应该是这样的: 蔬菜组:4 胡萝卜 3 酱汁状态:NS 酱汁状态:VI 酱汁状态:TA Bok Choy 3 酱汁状态:NS 酱汁状态:VI 酱汁状态:AC 茄子 3来源状态:QL 来源状态:NS 西兰花 3 来源状态:QL 集团谷物:1 没有! 4 来源不存在
  • 蔬菜组:4 --> 4 是组内产品的数量(蔬菜类别中有 4 种产品,即胡萝卜,白菜,鸡蛋植物,西兰花。胡萝卜 3,白菜 3 --> 3 是类别 ID 蔬菜类别的 CategoryID 为 3

标签: c# linq


【解决方案1】:

我仍然不确定您要实现什么,但要使用 LINQ 获得 left outer join,您需要使用 join ... intofrom ....DefaultIfEmpty()

您正在使用select ....DefaultIfEmpty(),这并不是您所需要的。

var leftOuterQuery =
    from category in categories
    join prod in products on category.ID equals prod.CategoryID into prodGroup
    from products in prodGroup.DefaultIfEmpty()       
    select new
    {
        Category = category.Name,
        Products = products.OrderBy(x => x.Name)
    }

【讨论】:

  • 嗨 Marcin.. 感谢您的快速回复。我想要实现的是我想要得到这样的结果: 类别蔬菜有 4 种产品:胡萝卜 3 来源:新南威尔士州,维多利亚州,塔斯马尼亚州 / 白菜 3 来源:新南威尔士州,维多利亚州,澳大利亚首都地区 / 茄子 3 来源:昆士兰州,SW / Broccoli 3 Source:QLD --> 请注意数字 3 是每个产品的 CategoryID! /// 谷物类别有 0 个产品,“Nothing,No product in this Category” 来源:“No product, No Source State” /// .. 我只是不能为“谷物”类别的产品集合列表分配一个字符串因为'Source'是一个集合,而不是一个字符串!... Alan
【解决方案2】:

这里发布了一个使用 linq 的左外连接的简单而整洁的扩展:http://www.codeproject.com/Tips/724333/Left-Outer-Join-extension-for-Entity-Framework 我想这可能会对你有所帮助。

【讨论】:

  • 嗨 Marcin .. 您能否提供完整的代码来展示如何不仅拥有类别信息,而且还拥有每个类别下的产品详细信息 - 即是否存在匹配项(包括产品名称和产品来源)? ?,如果没有匹配,只打印类别名称,但对于产品名称及其相关来源,而不是将其设置为空,打印一些文本,即“无产品”、“无来源状态”?
  • 嗨 Marcin .. 您能否提供完整的代码来展示如何不仅打印类别信息,而且还打印每个类别下的产品详细信息 - (包括产品名称和产品来源),如果有匹配??,如果一个类别没有产品匹配,只需打印类别名称,但对于产品名称及其相关来源,而不是将其设为空,打印一些文本,即“无产品”、“无来源状态”?我只想要一些类似于 SQL 左连接的结果,但是 C# 左连接在 LINQ 中听起来太难了,我无法得到我想要的......任何人请帮助这个......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-14
  • 2022-01-07
  • 1970-01-01
  • 2014-10-07
  • 2015-03-07
  • 1970-01-01
  • 2011-08-03
相关资源
最近更新 更多