首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linq-to-Entities Join vs GroupJoin

Linq-to-Entities Join vs GroupJoin
EN

Stack Overflow用户
提问于 2013-03-24 12:49:24
回答 2查看 120.1K关注 0票数 218

有人能解释一下GroupJoin()是什么吗?

它与常规的Join()有什么不同

它是常用的吗?

它只适用于方法语法吗?那么查询语法呢?(一个c#代码示例会更好)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-24 21:40:26

行为

假设您有两个列表:

代码语言:javascript
复制
Id  Value
1   A
2   B
3   C

Id  ChildValue
1   a1
1   a2
1   a3
2   b1
2   b2

当您在Id字段上Join这两个列表时,结果将是:

代码语言:javascript
复制
Value ChildValue
A     a1
A     a2
A     a3
B     b1
B     b2

当您在Id字段上GroupJoin这两个列表时,结果将是:

代码语言:javascript
复制
Value  ChildValues
A      [a1, a2, a3]
B      [b1, b2]
C      []

因此,Join会生成父值和子值的平面(表格)结果。

GroupJoin在第一个列表中生成一个条目列表,每个条目在第二个列表中具有一组连接的条目。

这就是为什么Join等同于SQL中的INNER JOIN:没有C条目。而GroupJoin等同于OUTER JOINC在结果集中,但是有一个空的相关条目列表(在GroupJoin结果集中应该有一个行C - null)。

语法

因此,让这两个列表分别为IEnumerable<Parent>IEnumerable<Child>。(对于Linq to Entities:IQueryable<T>)。

Join语法为

代码语言:javascript
复制
from p in Parent
join c in Child on p.Id equals c.Id
select new { p.Value, c.ChildValue }

返回一个IEnumerable<X>,其中X是具有两个属性ValueChildValue的匿名类型。此查询语法在幕后使用Join方法。

GroupJoin语法为

代码语言:javascript
复制
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }

返回一个IEnumerable<Y>,其中Y是一个匿名类型,由一个Parent类型的属性和一个IEnumerable<Child>类型的属性组成。此查询语法在幕后使用GroupJoin方法。

我们可以在后一个查询中只执行select g,它将选择一个IEnumerable<IEnumerable<Child>>,比如一个列表列表。在许多情况下,包含父级的select更有用。

一些用例

1.生成平面外连接。

如上所述,声明..。

代码语言:javascript
复制
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }

..。生成具有子组的父组列表。通过添加两个小代码,可以将其转换为父子对的平面列表:

代码语言:javascript
复制
from p in parents
join c in children on p.Id equals c.Id into g // <= into
from c in g.DefaultIfEmpty()               // <= flattens the groups
select new { Parent = p.Value, Child = c?.ChildValue }

结果类似于

代码语言:javascript
复制
Value Child
A     a1
A     a2
A     a3
B     b1
B     b2
C     (null)

注意,在上面的语句中重用了范围变量c。这样,任何join语句都可以简单地转换为outer join,方法是将into g from c in g.DefaultIfEmpty()的等价物添加到现有join语句中。

这就是查询(或综合)语法的闪光点。方法(或流畅的)语法显示了实际发生了什么,但它很难编写:

代码语言:javascript
复制
parents.GroupJoin(children, p => p.Id, c => c.Id, (p, c) => new { p, c })
       .SelectMany(x => x.c.DefaultIfEmpty(), (x,c) => new { x.p.Value, c?.ChildValue } )

所以在LINQ中一个扁平的outer join就是一个被SelectMany扁平化的GroupJoin

2.维护秩序

假设父级列表稍长一点。某些UI会以固定顺序将选定父项的列表作为Id值生成。让我们使用:

代码语言:javascript
复制
var ids = new[] { 3,7,2,4 };

现在,必须按此顺序从父项列表中过滤选定的父项。

如果我们这么做了..。

代码语言:javascript
复制
var result = parents.Where(p => ids.Contains(p.Id));

..。parents的顺序将决定结果。如果父母是按Id排序的,结果将是父母2,3,4,7。不好。但是,我们也可以使用join来过滤列表。通过使用ids作为第一个列表,该顺序将被保留:

代码语言:javascript
复制
from id in ids
join p in parents on id equals p.Id
select p

结果是父母3,7,2,4。

票数 425
EN

Stack Overflow用户

发布于 2013-03-24 18:06:00

根据eduLINQ的说法

要理解GroupJoin所做的事情,最好的方法就是考虑

。在那里,总体思路是我们查看“外部”输入序列,从“内部”序列中找到所有匹配的项(基于每个序列上的键投影),然后产生匹配元素对。GroupJoin也是类似的,只是它不是生成成对的元素,而是基于每个“外部”项和匹配的“内部”项的序列,为该“外部”项产生一个单独的结果。

唯一的区别在于return语句:

加入

代码语言:javascript
复制
var lookup = inner.ToLookup(innerKeySelector, comparer); 
foreach (var outerElement in outer) 
{ 
    var key = outerKeySelector(outerElement); 
    foreach (var innerElement in lookup[key]) 
    { 
        yield return resultSelector(outerElement, innerElement); 
    } 
} 

GroupJoin

代码语言:javascript
复制
var lookup = inner.ToLookup(innerKeySelector, comparer); 
foreach (var outerElement in outer) 
{ 
    var key = outerKeySelector(outerElement); 
    yield return resultSelector(outerElement, lookup[key]); 
} 

点击此处阅读更多信息:

  • Reimplementing LINQ to Objects: Part 19 - Join
  • Reimplementing LINQ to Objects: Part 22 - GroupJoin
票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15595289

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档