简体   繁体   English

连接中的实体框架子查询

[英]Entity Framework subquery in join

I have a problem using a subquery inside my join operator. 我在连接运算符中使用子查询时遇到问题。

I'd like to know how I can make my LINQ query better. 我想知道如何更好地使我的LINQ查询。

I want to become a query like this: 我想成为这样的查询:

SELECT Submissions.Title, SubmissionStatusEvents.ToStatus, SubmissionStatusEvents.ToStatusId, SubmissionStatusEvents.Created, SubmissionComments.Created, Content =
         CASE 
              WHEN SubmissionComments.Type = '1'
                 THEN SubmissionComments.Content
              ELSE NULL
         END, AspNetUsers.UserName, AspNetUsers.AvatarId , Projects.Name, Comapnies.LogoId
FROM Submissions
JOIN SubmissionComments ON SubmissionComments.Id =
    (
        select TOP 1 Id
        From SubmissionComments
        where SubmissionComments.SubmissionId = Submissions.Id
        Order by SubmissionComments.Created desc
    )
JOIN SubmissionStatusEvents ON SubmissionStatusEvents.Id =
    (
         select TOP 1 Id
         From SubmissionStatusEvents
         where SubmissionStatusEvents.SubmissionId = Submissions.Id
         Order by SubmissionStatusEvents.Created desc
    )
JOIN AspNetUsers ON SubmissionComments.CommenterId=AspNetUsers.Id
JOIN Projects ON  Projects.Id = Submissions.ProjectId
JOIN Companies ON Projects.CompanyId = Companies.ID

I tried it with following LINQ: 我尝试了以下LINQ:

(from submission in _ctx.Submissions
 join status in _ctx.SubmissionStatusEvents on (from s in _ctx.SubmissionStatusEvents where s.IsPublic && s.SubmissionId == submission.Id orderby s.Created descending select s.Id).First() equals status.Id
 join comment in _ctx.SubmissionComments on (from c in _ctx.SubmissionComments where c.IsPublic && c.SubmissionId == submission.Id orderby c.Created descending select c.Id).First() equals comment.Id
 join user in _ctx.Users on comment.CommenterId equals user.Id
 join project in _ctx.Projects on submission.ProjectId equals project.Id
 join company in _ctx.Companies on project.CompanyId equals company.Id
 where submission.SubmitterId == userId
 where status.IsPublic
 select new SubmissionWithLastEventChangeDto
 {
     Id = submission.Id,
     Title = submission.Ttile,
     Status = status.ToStatus,
     StatusId = status.ToStatusId,
     StatusChange = status.Created,
     ProjectId = project.Id,
     ProjectName = project.Name,
     ProjectType = project.Type,
     MaxPayout = project.ExceptionalPayout ?? project.CriticalPayout,
     LogoId = company.LogoId,
     LastComment = new LastEventChangeDto
     {
         UserName = user.UserName,
         AvatarId = user.AvatarId,
         Created = comment.Created,
         Type = comment.Type,
         Content = comment.Type == EntityEnum.SubmissionCommentType.Event ? comment.Content : null
     }
 }).ToListAsync();

However this LINQ query causes multiple queries: 但是,此LINQ查询会导致多个查询:

在此输入图像描述

I tried many things. 我尝试了很多东西。 Like using let as in this example Stack Overflow answer . 就像在这个例子中使用let一样Stack Overflow回答 My final attempt is based on this Stackoverflow answer 我的最后一次尝试是基于Stackoverflow的回答

I also tried to use .Take(1) instead of .First() 我也尝试使用.Take(1)代替.First()

If someone could point me in the correct direction I would be happy. 如果有人能指出我正确的方向,我会很高兴。 Sincerely, Brecht 真诚的,布莱希特

I would suggest utilizing the LINQ GroupJoin (similar to LINQ LEFT OUTER JOIN emulation, but instead of DefaultIfEmpty use OrderByDescending + Take ): 我建议使用LINQ GroupJoin (类似于LINQ LEFT OUTER JOIN仿真,但不使用DefaultIfEmpty使用OrderByDescending + Take ):

(from submission in db.Submissions
 join status in _ctx.SubmissionStatusEvents on submission.Id equals status.SubmissionId into statusGroup
 from status in statusGroup.OrderByDescending(status => status.Created).Take(1)
 join comment in _ctx.SubmissionComments on submission.Id equals comment.SubmissionId into commentGroup
 from comment in commentGroup.OrderByDescending(comment => comment.Created).Take(1)
... the rest (no change)

Of course the generated SQL query will be different (the construct translates to CROSS APPLY ) but the result should be the same. 当然生成的SQL查询将是不同的(构造转换为CROSS APPLY )但结果应该是相同的。

Your query feels a little odd (may be to do with the structure), but I would be tempted to try something like this: 您的查询感觉有点奇怪(可能与结构有关),但我很想尝试这样的事情:

(from submission in _ctx.Submissions
 where submission.SubmitterId == userId
 select new SubmissionWithLastEventChangeDto
 {
     Id = submission.Id,
     Title = submission.Ttile,
     Status = submission.SubmissionStatusEvents.OrderByDescending(e => e.Created).First().ToStatus,
     StatusId = submission.SubmissionStatusEvents.OrderByDescending(e => e.Created).First().ToStatusId,
     StatusChange = submission.SubmissionStatusEvents.OrderByDescending(e => e.Created).First().Status,,
     ProjectId = submission.Project.ProjectId,
     ProjectName = submission.Project.Name,
     ProjectType = submission.Project.Type,
     MaxPayout = submission.Project.ExceptionalPayout ?? submission.Project.CriticalPayout,
     LogoId = submission.Project.Company.LogoId,
     LastComment = new LastEventChangeDto(submission.SubmissionComments.OrderByDescending(e => e.Created).First())

 }).ToListAsync();

 //CTOR for this class
 public  LastEventChangeDto(SubmissionComment comment)
 {
          UserName = comment.User.UserName,
         AvatarId = comment.User.AvatarId,
         Created = comment.Created,
         Type = comment.Type,
         Content = comment.Type == EntityEnum.SubmissionCommentType.Event ? comment.Content : null
}

Might be a bit easier to follow than all the many joins in linq. 可能比linq中的所有连接更容易遵循。

I might also suggest a Dto to pass through your flatted status fields as well - could take a SubmissionStatus as a parameter. 我也可能建议Dto也可以通过你的平面状态字段 - 可以将SubmissionStatus作为参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM