2016-12-22 19 views
3

私の結合演算子内でサブクエリを使用する際に問題があります。Entity Frameworkのサブクエリでの結合

私はLINQクエリをより良くする方法を知りたいのですが。

私はこのようなクエリになりたい:

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 

私は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(); 

しかし、このLINQクエリは、複数のクエリが発生します。

enter image description here

私は多くのことを試みました。この例のようにletを使うのと同じようにStack Overflow answer。私の最後の試みが、私はまた、誰かが正しい方向に私を指すことができれば(1)の代わりに1次回の()

私は幸せになる.Takeを使用しようとしたthis Stackoverflow answer

に基づいています。 は誠意をこめて、 ブレヒト

+0

エンティティがこの長いクエリに対して1つのクエリを実行するように強制するのは難しいでしょう。それは、自動的に実行計画を構築することです –

答えて

1

はあなたのクエリは少し奇妙な感じ(構造をどうするかもしれない)が、私はこのような何かを試すように誘惑されるだろう:

(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 
} 

は従うことが少し簡単になりますlinqのすべての多くの結合よりも。

また、フラットなステータスフィールドを渡すようにDtoを提案することもできます。SubmissionStatusをパラメータとして使用できます。

3

私は(LINQ LEFT OUTER JOINエミュレーションに似て、代わりDefaultIfEmpty使用OrderByDescending + Takeの)LINQ GroupJoinを利用示唆している:構築物はCROSS APPLYに変換(もちろん

(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) 

生成されたSQLクエリは異なるものになります)しかし結果は同じでなければならない。

関連する問題