C# linq 省略的联接在使用 DefaultIfEmpty 时不起作用

本文关键字:DefaultIfEmpty 不起作用 linq | 更新日期: 2023-09-27 18:19:26

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

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

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

请注意,我在产品集合中将源作为列表集合。

我这里有两个问题:

  1. 当我使用 DefaultIfEmpty 时,如果 null Source集合不存在,我无法设置正确的引用 Souce - 但是,如果产品名称不存在,我可以引用一个有意义的字符串说"不存在"。任何人都可以帮助展示如果左连接找不到产品的来源,如何放置空字符串?
  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

C# linq 省略的联接在使用 DefaultIfEmpty 时不起作用

我仍然不确定您要实现的目标,但是要使用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)
    }

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