Linq-完全外连接

Linq-完全外连接

我有一个人的身份证和他们的名字的名单,和一个人的身份证和他们的姓氏的名单。有些人没有名字,有些人没有姓;我想在这两个列表上做一个完整的外部连接。

因此,以下清单:

ID  FirstName--  ---------
 1  John
 2  SueID  LastName--  --------
 1  Doe
 3  Smith

应产生:

ID  FirstName  LastName--  ---------  --------
 1  John       Doe
 2  Sue
 3             Smith

我是LINQ的新手(所以,如果我是跛脚的话,请原谅我),并且找到了很多“LINQ外部连接”的解决方案,这些解决方案看起来都很相似,但是看起来确实是外部联接。

到目前为止,我的尝试都是这样的:

private void OuterJoinTest(){
    List<FirstName> firstNames = new List<FirstName>();
    firstNames.Add(new FirstName { ID = 1, Name = "John" });
    firstNames.Add(new FirstName { ID = 2, Name = "Sue" });

    List<LastName> lastNames = new List<LastName>();
    lastNames.Add(new LastName { ID = 1, Name = "Doe" });
    lastNames.Add(new LastName { ID = 3, Name = "Smith" });

    var outerJoin = from first in firstNames
        join last in lastNames
        on first.ID equals last.ID        into temp        from last in temp.DefaultIfEmpty()
        select new
        {
            id = first != null ? first.ID : last.ID,
            firstname = first != null ? first.Name : string.Empty,
            surname = last != null ? last.Name : string.Empty
        };
    }}public class FirstName{
    public int ID;

    public string Name;}public class LastName{
    public int ID;

    public string Name;}

但这一结果是:

ID  FirstName  LastName--  ---------  --------
 1  John       Doe
 2  Sue

我做错什么了?


守着一只汪
浏览 1071回答 3
3回答

守候你守候我

我认为其中大多数都存在问题,包括公认的答案,因为它们在IQueryable上与Linq的工作不太好,这要么是因为执行了太多的服务器往返和太多的数据返回,要么是因为执行了太多的客户端执行。对于IEnumerable,我不喜欢Sehe的答案或类似的内容,因为它占用了过多的内存(一个简单的10000000双列表测试在我的32 GB机器上运行Linqpad)。另外,其他大多数并不实际实现正确的完全外部联接,因为它们使用的是带有右联接的UNION,而不是与右反半连接的UNION,这不仅从结果中消除了重复的内部联接行,而且消除了原来在左或右数据中存在的任何正确的重复。下面是我的扩展,它可以处理所有这些问题,生成SQL,就像在Linq中直接实现联接一样,在服务器上执行,并且比在EnDigable上的其他扩展更快,内存更少:public&nbsp;static&nbsp;class&nbsp;Ext&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TResult>&nbsp;LeftOuterJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IEnumerable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TKey>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TRight,&nbsp;TKey>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TRight,&nbsp;TResult>&nbsp;resultSelector)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;from&nbsp;left&nbsp;in&nbsp;leftItems &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;join&nbsp;right&nbsp;in&nbsp;rightItems&nbsp;on&nbsp;leftKeySelector(left)&nbsp;equals&nbsp;rightKeySelector(right)&nbsp;into&nbsp;temp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;right&nbsp;in&nbsp;temp.DefaultIfEmpty() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select&nbsp;resultSelector(left,&nbsp;right); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TResult>&nbsp;RightOuterJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IEnumerable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TKey>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TRight,&nbsp;TKey>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TRight,&nbsp;TResult>&nbsp;resultSelector)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;from&nbsp;right&nbsp;in&nbsp;rightItems &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;join&nbsp;left&nbsp;in&nbsp;leftItems&nbsp;on&nbsp;rightKeySelector(right)&nbsp;equals&nbsp;leftKeySelector(left)&nbsp;into&nbsp;temp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;left&nbsp;in&nbsp;temp.DefaultIfEmpty() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select&nbsp;resultSelector(left,&nbsp;right); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TResult>&nbsp;FullOuterJoinDistinct<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IEnumerable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TKey>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TRight,&nbsp;TKey>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TRight,&nbsp;TResult>&nbsp;resultSelector)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;leftItems.LeftOuterJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector).Union(leftItems. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RightOuterJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TResult>&nbsp;RightAntiSemiJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IEnumerable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TKey>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TRight,&nbsp;TKey>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TRight,&nbsp;TResult>&nbsp;resultSelector)&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;hashLK&nbsp;=&nbsp;new&nbsp;HashSet<TKey>(from&nbsp;l&nbsp;in&nbsp;leftItems&nbsp;select&nbsp;leftKeySelector(l)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;rightItems.Where(r&nbsp;=>&nbsp;!hashLK.Contains(rightKeySelector(r))).Select(r&nbsp;=>&nbsp;resultSelector((TLeft)null,r)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TResult>&nbsp;FullOuterJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IEnumerable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TKey>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TRight,&nbsp;TKey>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Func<TLeft,&nbsp;TRight,&nbsp;TResult>&nbsp;resultSelector)&nbsp;&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;leftItems.LeftOuterJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Concat(leftItems.RightAntiSemiJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;Expression<Func<TP,&nbsp;TC,&nbsp;TResult>>&nbsp;CastSMBody<TP,&nbsp;TC,&nbsp;TResult>(LambdaExpression&nbsp;ex,&nbsp;TP&nbsp;unusedP,&nbsp;TC&nbsp;unusedC, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TResult&nbsp;unusedRes)&nbsp;=>&nbsp;(Expression<Func<TP,&nbsp;TC,&nbsp;TResult>>)ex; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IQueryable<TResult>&nbsp;LeftOuterJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IQueryable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IQueryable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TKey>>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TRight,&nbsp;TKey>>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TRight,&nbsp;TResult>>&nbsp;resultSelector)&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;where&nbsp;TRight&nbsp;:&nbsp;class&nbsp;where&nbsp;TResult&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;sampleAnonLR&nbsp;=&nbsp;new&nbsp;{&nbsp;left&nbsp;=&nbsp;(TLeft)null,&nbsp;rightg&nbsp;=&nbsp;(IEnumerable<TRight>)null&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;parmP&nbsp;=&nbsp;Expression.Parameter(sampleAnonLR.GetType(),&nbsp;"p"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;parmC&nbsp;=&nbsp;Expression.Parameter(typeof(TRight),&nbsp;"c"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;argLeft&nbsp;=&nbsp;Expression.PropertyOrField(parmP,&nbsp;"left"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;newleftrs&nbsp;=&nbsp;CastSMBody(Expression.Lambda(Expression.Invoke(resultSelector,&nbsp;argLeft,&nbsp;parmC),&nbsp;parmP,&nbsp;parmC),&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleAnonLR,&nbsp;(TRight)null,&nbsp;(TResult)null); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;leftItems.AsQueryable().GroupJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;(left,&nbsp;rightg)&nbsp;=> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;{&nbsp;left,&nbsp;rightg&nbsp;}).SelectMany(r&nbsp;=>&nbsp;r.rightg.DefaultIfEmpty(),&nbsp;newleftrs); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IQueryable<TResult>&nbsp;RightOuterJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IQueryable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IQueryable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TKey>>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TRight,&nbsp;TKey>>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TRight,&nbsp;TResult>>&nbsp;resultSelector)&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;where&nbsp;TRight&nbsp;:&nbsp;class&nbsp;where&nbsp;TResult&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;sampleAnonLR&nbsp;=&nbsp;new&nbsp;{&nbsp;leftg&nbsp;=&nbsp;(IEnumerable<TLeft>)null,&nbsp;right&nbsp;=&nbsp;(TRight)null&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;parmP&nbsp;=&nbsp;Expression.Parameter(sampleAnonLR.GetType(),&nbsp;"p"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;parmC&nbsp;=&nbsp;Expression.Parameter(typeof(TLeft),&nbsp;"c"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;argRight&nbsp;=&nbsp;Expression.PropertyOrField(parmP,&nbsp;"right"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;newrightrs&nbsp;=&nbsp;CastSMBody(Expression.Lambda(Expression.Invoke(resultSelector,&nbsp;parmC,&nbsp;argRight),&nbsp;parmP,&nbsp;parmC),&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleAnonLR,&nbsp;(TLeft)null,&nbsp;(TResult)null); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;rightItems.GroupJoin(leftItems,&nbsp;rightKeySelector,&nbsp;leftKeySelector,&nbsp;(right,&nbsp;leftg)&nbsp;=>&nbsp;new&nbsp;{&nbsp;leftg,&nbsp;right&nbsp;}). &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SelectMany(l&nbsp;=>&nbsp;l.leftg.DefaultIfEmpty(),&nbsp;newrightrs); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IQueryable<TResult>&nbsp;FullOuterJoinDistinct<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IQueryable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IQueryable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TKey>>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TRight,&nbsp;TKey>>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TRight,&nbsp;TResult>>&nbsp;resultSelector)&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;where&nbsp;TRight&nbsp;:&nbsp;class&nbsp;where&nbsp;TResult&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;leftItems.LeftOuterJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector). &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Union(leftItems.RightOuterJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;Expression<Func<TP,&nbsp;TResult>>&nbsp;CastSBody<TP,&nbsp;TResult>(LambdaExpression&nbsp;ex,&nbsp;TP&nbsp;unusedP,&nbsp;TResult&nbsp;unusedRes)&nbsp;=> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Expression<Func<TP,&nbsp;TResult>>)ex; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IQueryable<TResult>&nbsp;RightAntiSemiJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IQueryable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IQueryable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TKey>>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TRight,&nbsp;TKey>>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TRight,&nbsp;TResult>>&nbsp;resultSelector)&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;where&nbsp;TRight&nbsp;:&nbsp;class&nbsp;where&nbsp;TResult&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;sampleAnonLgR&nbsp;=&nbsp;new&nbsp;{&nbsp;leftg&nbsp;=&nbsp;(IEnumerable<TLeft>)null,&nbsp;right&nbsp;=&nbsp;(TRight)null&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;parmLgR&nbsp;=&nbsp;Expression.Parameter(sampleAnonLgR.GetType(),&nbsp;"lgr"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;argLeft&nbsp;=&nbsp;Expression.Constant(null,&nbsp;typeof(TLeft)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;argRight&nbsp;=&nbsp;Expression.PropertyOrField(parmLgR,&nbsp;"right"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;newrightrs&nbsp;=&nbsp;CastSBody(Expression.Lambda(Expression.Invoke(resultSelector,&nbsp;argLeft,&nbsp;argRight),&nbsp;parmLgR), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleAnonLgR,&nbsp;(TResult)null); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;rightItems.GroupJoin(leftItems,&nbsp;rightKeySelector,&nbsp;leftKeySelector,&nbsp;(right,&nbsp;leftg)&nbsp;=> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;{&nbsp;leftg,&nbsp;right&nbsp;}).Where(lgr&nbsp;=>&nbsp;!lgr.leftg.Any()).Select(newrightrs); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IQueryable<TResult>&nbsp;FullOuterJoin<TLeft,&nbsp;TRight,&nbsp;TKey,&nbsp;TResult>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;IQueryable<TLeft>&nbsp;leftItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IQueryable<TRight>&nbsp;rightItems, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TKey>>&nbsp;leftKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TRight,&nbsp;TKey>>&nbsp;rightKeySelector, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<TLeft,&nbsp;TRight,&nbsp;TResult>>&nbsp;resultSelector)&nbsp;where&nbsp;TLeft&nbsp;:&nbsp;class&nbsp;where&nbsp;TRight&nbsp;:&nbsp;class&nbsp;where&nbsp;TResult&nbsp;:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;leftItems.LeftOuterJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Concat(leftItems.RightAntiSemiJoin(rightItems,&nbsp;leftKeySelector,&nbsp;rightKeySelector,&nbsp;resultSelector)); &nbsp;&nbsp;&nbsp;&nbsp;}}右反半连接之间的区别主要与linq在对象或源中的区别有关,但在最终答案中在server(Sql)端产生了差异,从而删除了不必要的内容。JOIN.手编码Expression若要处理合并Expression<Func<>>可以使用LinqKit对lambda进行改进,但是如果语言/编译器为此添加了一些帮助,那就太好了。这个FullOuterJoinDistinct和RightOuterJoin函数是为了完整性而包含的,但我没有重新实现。FullOuterGroupJoin现在还没有。我写另一个版本一个完全的外部连接IEnumerable对于键是可排序的情况下,这是大约50%的速度比组合左外部连接和右反半连接,至少在小集合。它只在排序一次之后就会遍历每个集合。
打开App,查看更多内容
随时随地看视频慕课网APP