【问题标题】:Condense Linq logic into one query将 Linq 逻辑压缩为一个查询
【发布时间】:2018-01-05 20:18:04
【问题描述】:

我将两个参数传递给一个方法,一个帐号或一个组织编号。一次只有一个参数可以有一个值。意思是,如果我传入一个帐号,则组织编号为空。反之亦然。

目前,我正在尝试对与个人或组织关联的一组帐户进行排序。我将与实体直接相关的帐户进行排序,然后对其进行排序。

// Accounts entity is directly involved with
mainAccounts = accounts
    .Where(acct => ((acct.PrimaryPersonNumber.HasValue) ? acct.PrimaryPersonNumber : acct.PrimaryOrganizationNumber) == entityNumber)
    .OrderBy(acct => acct.AccountNumber);

然后我查看附加到每个实体的RoleCode 变量以对其进行排序。

我遇到的问题是试图将这两个查询合并为一个,有点像我对第一个查询所做的。

if (persNbr.HasValue)
{
    // Accounts Person takes a role in
    secondaryAccounts = accounts
                        .Where(acct => acct.PrimaryPersonNumber != entityNumber)
                        .OrderBy(acct => acct.PersonRoles
                                             .Where(role => role.PersNbr == entityNumber)
                                             .Select(role => role.RoleOrder).Min())
                        .ThenBy(acct => acct.AccountNumber);
}
else
{
    // Accounts Organization takes a role in
    secondaryAccounts = accounts
                        .Where(acct => acct.PrimaryOrganizationNumber != entityNumber)
                        .OrderBy(acct => acct.OrganizationRoles
                                             .Where(role => role.OrgNbr == entityNumber)
                                             .Select(role => role.RoleOrder).Min())
                        .ThenBy(acct => acct.AccountNumber);

我尝试关注,但 C# 智能感知抱怨该对象(acct.PersonRolesacct.OrganizationRoles)不存在,并且直到运行时才会存在。

secondaryAccounts = accounts
    .Where(acct => ((acct.PrimaryPersonNumber.HasValue) ? acct.PrimaryPersonNumber : acct.PrimaryOrganizationNumber) != entityNumber)
    .OrderBy(acct => ((acct.PrimaryPersonNumber.HasValue) ? acct.PersonRoles : acct.OrganizationRoles) // <-- Intellisense can't get past this line
                     .Where(role => ((acct.PrimaryPersonNumber.HasValue) ? role.PersNbr : role.OrgNbr) == entityNumber)
                     .Select(role => role.RoleOrder).Min())
    .ThenBy(acct => acct.AccountNumber);

我该怎么做?

如果有帮助,这是我的方法。

private Account[] SortAccountsOnPersonRoles(Account[] accounts, long? persNbr, long? orgNbr)
{
    IEnumerable<Account> mainAccounts;
    IEnumerable<Account> secondaryAccounts;

    long entityNumber = (long)((persNbr.HasValue) ? persNbr : orgNbr);

    // Accounts entity is directly involved with
    mainAccounts = accounts
        .Where(acct => ((acct.PrimaryPersonNumber.HasValue) ? acct.PrimaryPersonNumber : acct.PrimaryOrganizationNumber )== entityNumber)
        .OrderBy(acct => acct.AccountNumber);

    if (persNbr.HasValue)
    {
        // Accounts Person takes a role in
        secondaryAccounts = accounts
                            .Where(acct => acct.PrimaryPersonNumber != entityNumber)
                            .OrderBy(acct => acct.PersonRoles
                                                 .Where(role => role.PersNbr == entityNumber)
                                                 .Select(role => role.RoleOrder).Min())
                            .ThenBy(acct => acct.AccountNumber);
    }
    else
    {
        // Accounts Organization takes a role in
        secondaryAccounts = accounts
                            .Where(acct => acct.PrimaryOrganizationNumber != entityNumber)
                            .OrderBy(acct => acct.OrganizationRoles
                                                 .Where(role => role.OrgNbr == entityNumber)
                                                 .Select(role => role.RoleOrder).Min())
                            .ThenBy(acct => acct.AccountNumber);
    }

    return mainAccounts.Concat(secondaryAccounts).ToArray();
}

编辑: Intellisense 的错误说:

无法确定条件表达式的类型,因为 PersonRoles[] 和 OrganizationRoles[] 之间没有隐式转换

这是因为我尝试了以下语句:

.OrderBy(acct => ((acct.PrimaryPersonNumber.HasValue) ? acct.PersonRoles : acct.OrganizationRoles) // <-- Intellisense can't get past this line
     .Where(role => ((acct.PrimaryPersonNumber.HasValue) ? role.PersNbr : role.OrgNbr) == entityNumber)

Intellisense 无法确定 lamda 变量的值来执行 LINQ 查询 .Where()。具体来说,

acct => ((acct.PrimaryPersonNumber.HasValue) ? acct.PersonRoles : acct.OrganizationRoles)

【问题讨论】:

  • 你能发布你从智能感知得到的确切错误信息吗?
  • 您不能从同一个 LINQ 表达式返回 PersonRolesOrganizationRoles,因为它们是不同的类型。这由于它们是数组而变得更加复杂,这意味着即使这两种类型是公共类型层次结构的一部分,也不容易为在不同情况下可能返回一个或另一个的表达式获得一致的返回类型.
  • @AaronM.Eshbach 是的,我想我可以使用他们的基类,但它会变得太复杂。

标签: c# .net linq sorting intellisense


【解决方案1】:

试试这个:

首先,创建两个具有不同参数的独立函数。

private Account[] SortAccountsOnPersonRolesByPersonNumber(Account[] accounts, 
    long personNbr) 

private Account[] SortAccountsOnPersonRolesByOrgNumber(Account[] accounts, 
    long orgNbr) 

然后,更改 main 函数,以便传入函数,而不是同时为 personNbrorgNbr 传递参数并计算哪些具有值(如果两者都做或都不做怎么办),而是传递函数。

我不知道逻辑是什么,所以我给参数起了相当无意义的名字。

private Account[] SortAccountsOnPersonRoles(Account[] accounts, 
    Func<Account, bool> accountComparison, 
    Func<Role, bool> roleComparison)

现在,您可以这样做:

   secondaryAccounts = accounts
       .Where(acct => accountComparison(acct))
       .OrderBy(acct => acct.PersonRoles
       .Where(role => roleComparison(role))
           .Select(role => role.RoleOrder).Min())
       .ThenBy(acct => acct.AccountNumber);

现在从两个新函数中调用“内部”函数并将这些条件作为参数传递。

private Account[] SortAccountsOnPersonRolesByPersonNumber(Account[] accounts, 
    long personNbr) 
{
    Func<Account, bool> accountComparison = acct => acct.PrimaryPersonNumber != personNbr;
    Func<Role, bool> roleComparison = role => role.PersNbr == personNbr;
    return SortAccountsOnPersonRoles(accounts, accountComparison, roleComparison);
}

【讨论】:

  • 我可以用这个。对于其他人来说有点复杂,并且引入了比我最初想要的更多的代码,但是 +1 的答案。
  • 我认为它最终会减少代码。而且每个单独的方法都短得多,这使得它们易于阅读。您不会传入两个可为空的参数,然后找出哪个有值,并且大多数查询都没有重复。条件分支也更少,这使得该方法更容易进行单元测试。这与组合查询无关。这是关于保持他们的共同点并将其余部分作为论据传递。但在这种情况下,参数不是值,它们是条件(函数)。
  • 我其实很喜欢这个答案。我会尝试实现它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多