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

问题描述 投票:3回答:1

语法是什么?在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

没有或部分,此方法有效,但缺少多余的键

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
c# sql entity-framework linq linq-to-sql
1个回答
0
投票

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

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

您确定要吗?如果fkDocumentId的值为10,它是指TransportId等于10的用户,还是WorkUserId等于10的用户,还是两者都引用?

[无论如何,如果您调查Enumerable.Join,,则会发现您提供了两个keySelector:一个用于从Users中选择一个密钥,另一个用于从UserDocuments中选择一个密钥。当这两个键相等时,则使用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,
        ...
    })
© www.soinside.com 2019 - 2024. All rights reserved.