2012-12-15 20 views
2

我想这个很简单的一块SQL来LINQ转换:转换SQL到LINQ查询时,我不能用“IN”

select * from Projects p 
inner join Documents d 
    on p.ProjectID = d.ProjectID 
left join Revisions r 
    on r.DocumentID = d.DocumentID 
    and r.RevisionID IN (SELECT max(r2.RevisionID) FROM Revisions r2 GROUP BY r2.DocumentID) 
WHERE p.ProjectID = 21 -- Query string in code 

这上面说,如果为一个文件存在的任何修订,还给我最高版本ID。由于它是左连接,如果不存在修订,我仍然希望返回结果。

这可以按预期工作,显示存在的任何修订(并返回最高版本ID),所有没有任何修订的文档也是如此。

当试图用LINQ写这个时,我只会得到文档修订版的结果。

这是迄今为止我尝试:

var query = from p in db.Projects 
           join d in db.Documents on new { ProjectID = p.ProjectID } equals new { ProjectID = Convert.ToInt32(d.ProjectID) } 
           join r in db.Revisions on new { DocumentID = d.DocumentID } equals new { DocumentID = Convert.ToInt32(r.DocumentID) } into r_join 
           from r in r_join.DefaultIfEmpty() 
           where 
           (from r2 in db.Revisions 
            group r2 by new { r2.DocumentID } 
             into g 
             select new { MaxRevisionID = g.Max(x => x.RevisionID) }).Contains(
             new { MaxRevisionID = r.RevisionID }) && 
           p.ProjectID == Convert.ToInt32(Request.QueryString["projectId"]) 
           select new { d.DocumentID, d.DocumentNumber, d.DocumentTitle, RevisionNumber = r.RevisionNumber ?? "<No rev>", Status = r.DocumentStatuse == null ? "<Not set>" : r.DocumentStatuse.Status }; 

我不是很擅长LINQ和使用转换器“Linqer”帮我出过,但我想收到以下消息时:

"SQL cannot be converted to LINQ: Only "=" operator in JOIN expression can be used. "IN" operator cannot be converted."

你会在修订表上看到我有.DefaultIfEmpty()。如果我删除执行分组的代码片段,无论文档是否存在修订,我都会得到所需的结果。但是,如果有链接,where子句应该返回文档的最高修订版本号,如果不是,我仍然要返回所有其他数据。与我的SQL代码不同,这不会发生。它只有在有修订表的链接时才会返回数据。

我希望有一点点意义。 组代码是搞乱我的结果集。无论是否有链接到修订表,我仍然希望我的结果返回。请帮忙!

谢谢。

=======

我现在使用的代码感谢Gert。

 var query = from p in db.Projects 
        from d in p.Documents 
        where p.ProjectID == Convert.ToInt32(Request.QueryString["projectId"]) 
        select new 
           { 
            p.ProjectID, 
            d.DocumentNumber, 
            d.DocumentID, 
            d.DocumentTitle, 
            Status = d.Revisions 
            .OrderByDescending(rn => rn.RevisionID) 
            .FirstOrDefault().DocumentStatuse.Status, 
            RevisionNumber = d.Revisions 
            .OrderByDescending(rn => rn.RevisionID) 
            .FirstOrDefault().RevisionNumber 
           }; 

     gvDocumentSelection.DataSource = query; 
     gvDocumentSelection.DataBind(); 

虽然这个作品,你会看到我通过运行相同的代码,但选择两个不同的领域选择从修订表中的两个领域。我猜测有更好,更有效的方法来做到这一点?理想情况下,我希望加入修订表,以防我需要访问更多字段,但是我再次遇到同样的分组问题。

  Status = d.Revisions 
      .OrderByDescending(rn => rn.RevisionID) 
      .FirstOrDefault().DocumentStatuse.Status, 
      RevisionNumber = d.Revisions 
      .OrderByDescending(rn => rn.RevisionID) 
      .FirstOrDefault().RevisionNumber 

最后的工作代码:

 var query = from p in db.Projects 
        from d in p.Documents 
        where p.ProjectID == Convert.ToInt32(Request.QueryString["projectId"]) 
        select new 
           { 
            p.ProjectID, 
            d.DocumentNumber, 
            d.DocumentID, 
            d.DocumentTitle, 
            LastRevision = d.Revisions 
         .OrderByDescending(rn => rn.RevisionID) 
         .FirstOrDefault() 
           }; 

     var results = from x in query 
         select 
          new 
           { 
            x.ProjectID, 
            x.DocumentNumber, 
            x.DocumentID, 
            x.DocumentTitle, 
            x.LastRevision.RevisionNumber, 
            x.LastRevision.DocumentStatuse.Status 
           }; 

     gvDocumentSelection.DataSource = results; 
     gvDocumentSelection.DataBind(); 

回答

1

如果你有1:N的导航性能有一个更简单(推荐)来实现这种方式:

from p in db.Projects 
from d in p.Documents 
select new { p, d, 
      LastRevision = d.Revisions 
          .OrderByDescending(r => r.RevisionId) 
          .FirstOrDefault() } 

无导航属性是类似的:

from p in db.Projects 
join d in db.Documents on new { ProjectID = p.ProjectID } 
        equals new { ProjectID = Convert.ToInt32(d.ProjectID) } 
select new { p, d, 
      LastRevision = db.Revisions 
       .Where(r => d.DocumentID = Convert.ToInt32(r.DocumentID)) 
       .OrderByDescending(r => r.RevisionId) 
       .FirstOrDefault() } 

编辑
你可以修改各类预测的,这样很宽的基本查询:

from x in query select new { x.p.ProjectName, 
          x.d.DocumentName, 
          x.LastRevision.DocumentStatus.Status, 
          x.LastRevision.FieldA, 
          x.LastRevision.FieldB 
          } 
+0

感谢格特。这非常接近,非常感谢,谢谢。但是,我试图从Revisions表中选择两个字段(这就是为什么我想要连接),我还需要修订表中的状态字段。什么是完成这个最好的方法?我试过'Status = d.Revisions.Select(s => s.DocumentStatuse.Status)'但是得到一个错误:'System.Data.Linq.SqlClient.Implementation.ObjectMaterializer1 + d__01 [System.Data.SqlClient.SqlDataReader ,System.String]'。谢谢(如果我在d.Revisions中添加'from r'就没有分组,我又回到了原来的位置)。 – Ricky

+0

我得到它的工作,但我不认为它现在是有效的,现在我从同一个表中选择两个字段(我可能需要更多,因此连接)。我更新了我的问题,请参阅我使用的代码。再次感谢! – Ricky

+0

请参阅我的编辑。 –