如何和我将“或”运算符引入 linq 查询连接

Posted

技术标签:

【中文标题】如何和我将“或”运算符引入 linq 查询连接【英文标题】:How and I introduce an "or" operator into a linq query join 【发布时间】:2020-06-16 09:50:21 【问题描述】:

在 linq 查询连接中引入“或”运算符的语法是什么。它似乎不喜欢“||”,“或”?我需要将一个外键与用户表中的两个可能键连接起来。

var thirdQuery = (from u in tbl_users
join ua in tbl_userDocuments on (u.TransportUserID equals ua.fkDocumentID
                             || u.WorkUserID equals ua.fkDocumentID) into uaGroup
from uaTrans in uaGroup.DefaultIfEmpty()
join ul in tbl_user_logins on uaTrans.fkUserID equals ul.user_login_id_pk into ulGroup

没有 or 部分,这可以工作,但缺少额外的键

var thirdQuery = (from u in tbl_users
join ua in tbl_userDocuments on (u.TransportUserID equals ua.fkDocumentID) into uaGroup
from uaTrans in uaGroup.DefaultIfEmpty()
join ul in tbl_user_logins on uaTrans.fkUserID equals ul.user_login_id_pk into ulGroup

【问题讨论】:

见我的SQL to LINQ Recipe - 基本上你必须做一个交叉连接并将OR条件放在Where中。 ***.com/questions/1264993/… 【参考方案1】:

因此,您的数据库至少包含两个表:UsersUserDocuments。每个UserDocument 都有一个属性fkDocumentId

虽然你没有这么说,但在我看来,这是表Users 中元素的外键。显然,这个外键有时指的是User.TransportUserId,有时指的是User.WorkUserId

你确定要这个吗?如果fkDocumentId 的值为10,它是指TransportId 等于10 的用户,还是指WorkUserId 等于10 的用户,或两者兼而有之?

不管怎样,如果你调查Enumerable.Join,,你会发现你提供了两个keySelector:一个从Users中选择一个key,一个从UserDocuments中选择一个key。当这两个键相等时,使用 ResultSelector 参数来构造您的连接元素。

问题在于“相等”这两个词。您必须确保选择您的键并提供一个 IEqualityComparer 以便将这些键视为相等。

另一种更简单的方法是创建一个新的 Join 扩展方法。

IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult> Join(
    this IEnumerable<TSource> outer,
    IEnumerable<TInner> inner,
    Func<TOuter, TKey> outerKeySelector1,
    Func<TOuter, TKey> outerKeySelector2,
    Func<TInner, TKey> innerKeySelector,
    Func<TOuter, TInner, TResult> resultSelector)

    // make two lookup tables from Outer: one for key1 and one for key2:
    var lookup1 = outer.ToLookup( outerElement => outerKeySelector1(outerElement));
    var lookup2 = outer.ToLookup( outerElement => outerKeySelector2(outerElement));

    // so if you have a TKey from the innerKeySelector, you can find if it matches key1 or key2
    foreach (TInner innerElement in inner)
    
        TKey innerKey = innerKeySelector(innerElement)
        var matchingElementsKey1 = lookup1[innerKey];
        var matchineElementsKey2 = lookup2[innerKey];
        var allmatchingElements = matchingElementsKey1.Concat(matchingElementsKey2);

        foreach(var matchingElement in allMatchingElements)
        
            TResult result = resultSelector(matchingElement, innerElement);
            yield return result;
        
    

用法:

var result = tblUsers.Join(tblUserDocuments,
    user => user.TransportUserId,           // select outerKey1
    user => user.WorkUserId,                // select outerKey2
    document => document.fkDocumentId,      // select innerKey

    // when inner key matches either outerKey1, or outerKey2, create one new object:
    (user, document) => new
    
        // Select the user documents that you want:
        UserId = user.Id,
        Name = user.Name,
        ...

        // Select the document properties that you want:
        DocumentId = document.Id,
        Author = document.Author,
        PublishedDate = document.Date,
        ...
    )

【讨论】:

你确定要这个吗? - 没有选择,这是我们团队采用的一个非常大的遗留应用程序。 fkDocumentId 是指 TransportId 还是 WorkUserId?它可以是或者为空。感谢您抽出宝贵时间提供帮助。

以上是关于如何和我将“或”运算符引入 linq 查询连接的主要内容,如果未能解决你的问题,请参考以下文章

Linq 动态查询问题 - 运算符“或”与操作数类型“布尔”和“字符串”不兼容

标准查询运算符---LINQ

在 Azure 表服务 linq 查询中运行包含运算符

如何在 C# 或 Linq 中比较大于或小于运算符值的两个字节数组?

如何有条件地应用 Linq 运算符?

关系型数据库进阶连接运算及查询实例