【问题标题】:How to combine LEFT JOIN, GROUP BY and SUM in LINQ?如何在 LINQ 中结合 LEFT JOIN、GROUP BY 和 SUM?
【发布时间】:2018-12-24 13:19:22
【问题描述】:

我想在 C# 中使用 LINQ 编写我的 SQL 查询。

这是我的查询(对于每个组织,从“收入”表中显示其 ID、名称、董事、分析师和总收入):

SELECT
    o.Id,
    o.Name,
    d.FirstName + ' ' + d.LastName AS Director,
    a.FirstName + ' ' + a.LastName AS Analyst,
    SUM(i.Amount) AS TotalIncome
FROM Organization o
    LEFT JOIN Employee d ON o.DirectorId = d.Id
    LEFT JOIN Employee a ON o.AnalystId = a.Id
    LEFT JOIN Income i ON o.Id = i.OrganizationId
GROUP BY
    o.Id, 
    o.Name, 
    d.FirstName,
    d.LastName,
    a.FirstName,
    a.LastName

我已经尝试过这样的事情:

from o in Organization
join director in Employee on o.DirectorId equals director.Id into directorJoin
from d in directorJoin.DefaultIfEmpty()
join analyst in Employee on o.AnalystId equals analyst.Id into analystJoin
from a in analystJoin.DefaultIfEmpty()
join income in Income on o.Id equals income.OrganizationId into incomeJoin
group o by new 
{
    o.Id,
    o.Name,
    Director = d.FirstName + ' ' + d.LastName,
    Analyst = a.FirstName + ' ' + a.LastName,
    TotalIncome = (decimal?)incomeJoin.Sum(x => x.Amount)
} into g
  select g.Key

但是我的程序抛出了一个异常:

不支持嵌套查询。 Operation1='GroupBy' Operation2='MultiStreamNest'

我将非常感谢任何帮助。

【问题讨论】:

  • 我刚刚使用了您的查询,但没有收到任何语法错误。能否提供样本数据?
  • 不要加入。使用导航属性。如果你有类似 Organisation.Incomes 的东西,这个查询就变得非常简单。顺便说一句,该错误是由分组表达式内部的聚合语句引起的。就像在 SQL 中一样,它不属于那里。
  • @SurajKumar 没有语法错误,但是在实体框架执行期间抛出异常。
  • @GertArnold 谢谢我最终使用了导航属性。我只是好奇使用这种方法是否存在任何性能问题。
  • 导航属性转换为 SQL 中的JOIN 语句,因此它们的性能不应该比手动连接语句差。

标签: sql sql-server entity-framework linq


【解决方案1】:

我最终使用了Gert Arnold 建议的Navigation Properties。这是我的问题及其解决方案的简化版本:

型号:

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Income
{
    public int Id { get; set; }
    public int OrganizationId { get; set; }
    public decimal Amount { get; set; }
}

public class Organization
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int AnalystId { get; set; }
    public virtual Employee Analyst { get; set; }

    public int DirectorId { get; set; }
    public virtual Employee Director { get; set; }

    public virtual ICollection<Income> Incomes { get; set; }
}

查询:

class Program
{
    static void Main(string[] args)
    {
        var context = new Context();

        var queryResult = context.Organizations.Select(x => new
        {
            x.Id,
            x.Name,
            Director = x.Director.FirstName + " " + x.Director.LastName,
            Analyst = x.Analyst.FirstName + " " + x.Analyst.LastName,
            TotalIncome = x.Incomes.Sum(y => y.Amount)
        });

    }
}

【讨论】:

  • 很好,我不知道。修正了我的答案。再次感谢
【解决方案2】:

您不想在组键内进行求和 - 在组外进行

from o in Organization
join director in Employee on o.DirectorId equals director.Id into directorJoin
from d in directorJoin.DefaultIfEmpty()
join analyst in Employee on o.AnalystId equals analyst.Id into analystJoin
from a in analystJoin.DefaultIfEmpty()
join income in Income on o.Id equals income.OrganizationId into incomeJoin
group o by new 
{
    o.Id,
    o.Name,
    Director = d.FirstName + ' ' + d.LastName,
    Analyst = a.FirstName + ' ' + a.LastName,
    i.Amount
} into g
  select new 
{
    g.Key.Id,
    g.Key.Name,
    g.Key.Director,
    g.Key.Analyst,
    TotalIncome = (decimal?)g.Sum(i => i.Amount)
}

您可能还需要检查空值,因为您将左连接到 d、i 和 a

【讨论】:

    猜你喜欢
    • 2021-05-03
    • 2021-01-30
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    相关资源
    最近更新 更多