使用LINQ表达式进行多个左连接并使用ISNULL功能

时间:2018-01-31 20:04:22

标签: c# asp.net entity-framework linq entity-framework-core

我正在构建一个步骤跟踪Web应用程序。我正在使用最新的EF Core。我正在与三个表进行交互:

  1. wg:WellnessGroup(WellnessGroupId,Name)
  2. wgu:WellnessGroupUser(查询表:WellnessGroupId,EmployeeId)
  3. wsl:WellnessStepsLog(EmployeeId,StepCount)
  4. 我想要的是获得所有WellnessGroups以及该组的总步数。如果还没有附加到该组的步骤,我希望NULL值为0.我有这个SQL语句,它给了我所需的数据:

    SELECT wg.Name, SUM(ISNULL(wsl.StepCount, 0)) AS steps
    FROM dbo.WellnessGroup AS wg
    LEFT JOIN dbo.WellnessGroupUser AS wgu
    ON wgu.WellnessGroupId = wg.Id
    LEFT JOIN dbo.WellnessStepsLog AS wsl
    ON wsl.EmployeeId = wgu.AzureAdUserId
    GROUP BY wg.Name
    ORDER BY steps DESC;
    

    我已经设法在我的控制器上放了两个LINQ表达式,它只给我一些与它们相关联的步骤的WellnessGroups,并且如果没有步骤则不给我WellnessGroup数据:

     var query = _dbContext.WellnessGroupUser
                        .Include(x => x.WellnessGroup)
                    .Join(_dbContext.WellnessStepsLog, group => 
                    group.AzureAdUserId, steps => steps.EmployeeId,
                        (group, steps) => new
                        {
                            Steps = steps.StepCount,
                            Date = steps.TrackedDate,
                            Group = group.WellnessGroup.Name
    
                        }).Where(x => x.Date >= yearToDate).Where(x => x.Date <= endDate);
    
     var stepsByGroup = query
                    .GroupBy(x => x.Group)
                    .Select(s => new
                    {
                        Group = s.Key,
                        Date = s.Max(x => x.Date),
                        Steps = s.Sum(x => x.Steps)
                    });
    

1 个答案:

答案 0 :(得分:0)

一种方法是查询所有WellnessGroups并将内部构建为第二个子查询。像这样:

var query =
    db.WellnessGroup.Select(wg => new {
        wg.WellnessGroupId,
        sum = (int?) wg.WellnessGroupUser
                       .Sum(wgu => wgu.Employee.WellnessStepsLog.Sum(wsl => wsl.StepCount))
    });

注意,转换为(int?)很重要。否则,sum假定为int,如果没有行的总和,则会导致InvalidOperationException。

另一种方法是首先构建所有总和。然后使用WellnessGroups进行外部联接:

// sum up all stepcounts
var q1 =
    from wgu in db.WellnessGroupUser
    from wsl in db.WellnessStepsLog
    where wgu.EmployeeId == wsl.EmployeeId
    group wsl.StepCount by wgu.WellnessGroupId
    into g
    select new {WellnessGroupId = g.Key, Sum = g.Sum()};

// join with all WellnessGroups
var q2 =
    from wg in db.WellnessGroup
    join s in q1 on wg.WellnessGroupId equals s.WellnessGroupId into sj
    from sum in sj.DefaultIfEmpty()
    select new {wg, sum = (int?) sum.Sum};

编辑:

由于OP后来在评论中询问如何按多个字段进行分组。以下是按WellnessGroup.WellnessGroupIdWellnessStepsLog.TrackedDate月份分组的示例。 GroupBy中的字段可以放在new { ... }中,可以有多个字段。因此,第一个查询为每个可能的WellnessGroup / Month组合创建一个行。第二个查询与之前一样执行WellnessGroup的外连接:

var q1 =
    from wgu in db.WellnessGroupUser
    from wsl in db.WellnessStepsLog
    where wgu.EmployeeId == wsl.EmployeeId
    group wsl.StepCount by new { wgu.WellnessGroupId, wsl.TrackedDate.Month }
    into g
    select new {g.Key.WellnessGroupId, g.Key.Month, Sum = g.Sum()};

// join with all WellnessGroups
var q2 =
    from wg in db.WellnessGroup
    join s in q1 on wg.WellnessGroupId equals s.WellnessGroupId into sj
    from sum in sj.DefaultIfEmpty()
    select new {wg.WellnessGroupId, Month = (int?) sum.Month, Sum = (int?) sum.Sum};