LINQ JOIN和OUTER JOIN - 如何将SQL转换为LINQ表达式

时间:2014-09-30 21:32:34

标签: c# sql linq linq-to-sql entity-framework-6

我想将以下SQL查询转换为LINQ表达式(使用Entity Framework 6.1)。到目前为止,我一直无法找到一个可以产生类似结果的可接受的LINQ表达式。任何将这个简单的SQL语句转换为LINQ express的帮助都将不胜感激。

SELECT AAG.Id AS GroupId,
   A.Id AS ActivityId,
   A.Title As Title,
   CASE WHEN AA.CompletedOn IS NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Completed,
   COALESCE(AAG.PointValue, 0) + SUM(COALESCE(AQ.PointValue, 0)) AS PointTotal
FROM ActivityAssignmentGroup AAG
INNER JOIN ActivityAssignment AA ON AA.GroupId = AAG.Id
INNER JOIN Activity A ON AA.ActivityId = A.Id
LEFT OUTER JOIN ActivityQuestion AQ ON AQ.ActivityId = A.Id
WHERE AAG.AssignedToId = 6
GROUP BY AAG.Id, A.Id, A.Title, CASE WHEN AA.CompletedOn IS NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, COALESCE(AAG.PointValue,0)

没有LEFT OUTER JOIN部分,下面的LINQ语句已部分完成,但我无法找出添加LEFT OUTER JOIN条件的相应语法:

var assignments = await (from g in db.AssignmentGroups.AsNoTracking().Where(x => x.AssignedToId == studentTask.Result.PersonId)
                                 join aa in db.ActivityAssignments.AsNoTracking() on g.Id equals aa.GroupId
                                 join a in db.Activities.AsNoTracking() on aa.ActivityId equals a.Id
                                 select new ActivityListViewModel
                                 {
                                     Id = a.Id,
                                     Points = g.PointValue ?? 0,
                                     Title = a.Title,
                                     GroupId = g.Id,
                                     Complete = (aa.CompletedOn != null)
                                 });

编辑:

感谢鲍勃的回应。我尝试使用DefaultIfEmpty并查看实体框架生成的结果SQL查询,但它没有工作。在发表这篇文章之前,这是我尝试过的LINQ语句:

var assignments = from g in db.AssignmentGroups.AsNoTracking().Where(x => x.AssignedToId == studentTask.Result.PersonId)
              join aa in db.ActivityAssignments.AsNoTracking() on g.Id equals aa.GroupId
              join a in db.Activities.AsNoTracking() on aa.ActivityId equals a.Id
              from aq in db.ActivityQuestions.Where(q => q.ActivityId == a.Id).DefaultIfEmpty()
              group aq by new { ActivityId = aq.ActivityId, Title = a.Title, GroupId = g.Id, Points = g.PointValue ?? 0, Completed = (aa.CompletedOn != null) } into s
              select new ActivityListViewModel
              {
                  Id = s.Key.ActivityId,
                  Points = s.Key.Points + s.Sum(y => y.PointValue ?? 0), //g.PointValue ?? 0, 
                  Title = s.Key.Title,
                  GroupId = s.Key.GroupId,
                  Complete = s.Key.Completed
              };

当然,它也没有用。结果是项目缺少Id(ActivityId)。

2 个答案:

答案 0 :(得分:1)

你需要使用DefaultIfEmpty()将连接转换为左外连接,来自MSDN的文档here

var assignments = await (from g in db.AssignmentGroups.AsNoTracking().Where(x => x.AssignedToId == studentTask.Result.PersonId)
                             join aa in db.ActivityAssignments.AsNoTracking() on g.Id equals aa.GroupId
                             join a1 in db.Activities.AsNoTracking() on aa.ActivityId equals a1.Id into a2
                             from a in a2.DefaultIfEmpty()
                             select new ActivityListViewModel
                             {
                                 Id = a == null ? null : a.Id,
                                 Points = g.PointValue ?? 0,
                                 Title = a == null ? null : a.Title,
                                 GroupId = g.Id,
                                 Complete = (aa.CompletedOn != null)
                             });

答案 1 :(得分:0)

关闭循环(谢谢Bob Vale)......下面的查询有效:

var assignments = from g in db.AssignmentGroups.AsNoTracking().Where(x => x.AssignedToId == studentTask.Result.PersonId)
                          join aa in db.ActivityAssignments.AsNoTracking() on g.Id equals aa.GroupId
                          join a in db.Activities.AsNoTracking() on aa.ActivityId equals a.Id
                          from aq in db.ActivityQuestions.Where(q => q.ActivityId == a.Id).DefaultIfEmpty()
                          group aq by new { ActivityId = a.Id, Title = a.Title, GroupId = g.Id, Points = g.PointValue ?? 0, Completed = (aa.CompletedOn != null) } into s
                          select new ActivityListViewModel
                          {
                              Id = s.Key.ActivityId,
                              Points = s.Key.Points + s.Sum(y => y.PointValue ?? 0), //g.PointValue ?? 0, 
                              Title = s.Key.Title,
                              GroupId = s.Key.GroupId,
                              Complete = s.Key.Completed
                          };

当我应该使用a.Id时,问题是按条件分组并使用ag.ActivityId。