2012-12-15 38 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

請參閱我的編輯。 –