![](/img/trans.png)
[英]How does LINQ's left-join `join … into` and `DefaultIfEmpty()` work?
[英]C# linq left out join does not work using DefaultIfEmpty
我是C#的新手,并且有一个查询要在LINQ中使用左联接。
我有两个数据源-一个是类别集合,一个是产品集合。 我想将这两个数据源连接在一起,以便获得如下结果:
Category Name (Fruit) - Product Name ( peach)- Source ( QLD,NSW).
请注意,我在产品集合中有“作为列表收集来源”。
我这里有两个问题:
DefaultIfEmpty
,如果Souce
不存在,则无法为null Source
集合设置正确的引用-但是,如果不存在有意义的字符串(例如“不存在”),则可以引用产品名称。 如果左联接找不到产品的来源,任何人都可以帮助显示如何放置空字符串? 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
我仍然不确定您要实现的目标,但是要使用LINQ进行left outer join
联接,您需要在from ....DefaultIfEmpty()
使用join ... into
from ....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我想这可能对您有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.