2011-03-24 71 views
2

我有以下LINQ查詢,即返回我期望的結果,但它不「感覺」正確。這是LINQ查詢「正確」嗎?

基本上它是一個左連接。我需要UserProfile表中的所有記錄。

然後LastWinnerDate是來自勝出者表(可能的多個記錄)的單個記錄,指示DateTime最後一條記錄在該表中爲用戶輸入。

WinnerCount是獲勝者表中用戶的記錄數(可能有多個記錄)。

Video1基本上是一個布爾值,表示在第三個表上匹配的勝者表中的用戶存在或不是記錄目標(應該是1行或0行)。

Quiz1與視頻1匹配來自Objective Table的另一條記錄(應該是1行或0行)。

視頻和測驗重複了12次,因爲它是向用戶顯示報告,列出所有用戶記錄並指出他們是否達到了目標。

var objectiveIds = new List<int>(); 
objectiveIds.AddRange(GetObjectiveIds(objectiveName, false)); 

var q = 
    from up in MetaData.UserProfile 
    select new RankingDTO 
    { 
     UserId = up.UserID, 
     FirstName = up.FirstName, 
     LastName = up.LastName, 
     LastWinnerDate = (
      from winner in MetaData.Winner 
      where objectiveIds.Contains(winner.ObjectiveID) 
      where winner.Active 
      where winner.UserID == up.UserID 
      orderby winner.CreatedOn descending 
      select winner.CreatedOn).First(), 
     WinnerCount = (
      from winner in MetaData.Winner 
      where objectiveIds.Contains(winner.ObjectiveID) 
      where winner.Active 
      where winner.UserID == up.UserID 
      orderby winner.CreatedOn descending 
      select winner).Count(), 
     Video1 = (
      from winner in MetaData.Winner 
      join o in MetaData.Objective on winner.ObjectiveID equals o.ObjectiveID 
      where o.ObjectiveNm == Constants.Promotions.SecVideo1 
      where winner.Active 
      where winner.UserID == up.UserID 
      select winner).Count(), 
     Quiz1 = (
      from winner2 in MetaData.Winner 
      join o2 in MetaData.Objective on winner2.ObjectiveID equals o2.ObjectiveID 
      where o2.ObjectiveNm == Constants.Promotions.SecQuiz1 
      where winner2.Active 
      where winner2.UserID == up.UserID 
      select winner2).Count(), 
    }; 
+1

哪一部分不_feel right_ =) – gideon 2011-03-24 14:19:56

+4

嘗試[代碼審查(http://codereview.stackexchange.com/ ) – 2011-03-24 14:20:10

+0

我如何完成左連接。我仍然在學習LINQ,而在T-SQL中,我只是在查詢的主要部分寫入JOINS ... – Schenz 2011-03-24 14:21:40

回答

1

您幾次重複join winners table部分。爲了避免它,你可以把它分成幾個結果Selects。因此,您可以使用較少的代碼進行兩次選擇,而不是有一個巨大的選擇。在您的例子中,我首先會中選擇winner2變量選擇其他結果屬性之前:

var q1 = 
    from up in MetaData.UserProfile 
    select new {up, 
       winners = from winner in MetaData.Winner 
         where winner.Active 
         where winner.UserID == up.UserID 
         select winner}; 
var q = from upWinnerPair in q1 
    select new RankingDTO 
    { 
     UserId = upWinnerPair.up.UserID, 
     FirstName = upWinnerPair.up.FirstName, 
     LastName = upWinnerPair.up.LastName, 
     LastWinnerDate = /* Here you will have more simple and less repeatable code 
          using winners collection from "upWinnerPair.winners"*/ 
+0

這將不會選擇任何用戶記錄也不具有贏家記錄。我需要執行外部聯接來檢索所有用戶記錄,而不管他們是否有贏家記錄。 – Schenz 2011-03-24 14:25:36

+0

@Schenz,你仍然可以將外部聯接提取到第一個語句中。這個想法依然如此。 – Snowbear 2011-03-24 14:28:29

+0

我試圖看到它,但我仍然在學習LINQ,並且它對我來說並不明顯... – Schenz 2011-03-24 14:30:22

1

查詢本身很簡單:只是一個主要外部查詢等一系列子查詢的檢索實際列數據。雖然它不是查詢數據的最有效方法(連接和使用窗口函數可能會使性能更好),但它是使用查詢或表達式語法表示查詢的唯一真實方法(SQL中的窗口函數在LINQ或支持LINQ的擴展方法中沒有映射)。

請注意,您沒有在代碼中執行任何實際的外部連接(左側或右側)您正在創建子查詢來檢索列數據。可能值得看看由查詢生成的實際SQL。你不指定你正在使用哪個ORM(這將決定如何檢查它的客戶端)或你正在使用哪個數據庫(這將決定如何檢查它在服務器端)。

如果您使用的是ADO.NET Entity Framework,則可以將查詢轉換爲ObjectQuery並致電ToTraceString()

如果您正在使用SQL Server,你可以使用SQL Server Profiler(假設你可以訪問它)來查看正在執行的SQL,也可以手動運行跟蹤做同樣的事情。

要執行一個外部聯接在LINQ查詢語法,這樣做:

假設我們有兩個來源alphabeta,每個都具有一個共同的Id屬性,你可以從alpha選擇並執行一個左中加入關於beta這樣:

from a in alpha 
join btemp in beta on a.Id equals btemp.Id into bleft 
from b in bleft.DefaultIfEmpty() 

select new { IdA = a.Id, IdB = b.Id } 

不可否認,語法有點偏斜。儘管如此,它的工作原理,並在SQL將被翻譯成這樣的:

select 
    a.Id as IdA, 
    b.Id as Idb 

from alpha a 

left join beta b on a.Id = b.Id 
+0

我使用LLBL作爲ORM,並不確定如何檢查... – Schenz 2011-03-24 14:32:07

+1

@Schenz :它看起來像使用.NET跟蹤機制生成SQL的LLBL輸出。你可以實現一個簡單的'TraceListener'類並從中監控SQL。 http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx – 2011-03-24 15:02:09

0

它看起來好像沒什麼問題,但我能看到爲什麼多個子查詢可以在一個編碼器的眼睛觸發效率低下的擔心。

看看產生什麼SQL,但(我猜你正在運行此對您的說法「表」上述數據庫源),你開始擔心之前。查詢提供程序可以非常擅長生成高效的SQL,從而生成一個好的底層數據庫查詢,如果發生這種情況,那麼快樂的日子(它也會給你另一個確定正確性的看法)。