2011-02-17 50 views
1

設置很簡單,主表和一個鏈接的子表(一個主,很多子)。比方說,我們想要提取所有的主人和他們的時間順序的兒童價值(更新,訪問等)。查詢應該是這樣的(例如):如果主人有沒有孩子發生限制結果集中的NULL子查詢

var masters = from m in Master 
       let mc = m.Childs.Max(c => c.CreatedOn) 
       select new { m, mc }; 

一個潛在的問題,子查詢將產生NULL和轉換從NULL爲DateTime將失敗,並

InvalidOperationException異常:空值 值不能分配給類型爲System.DateTime的成員 ,該值爲 非空值類型。

解決例外情況是鑄MC到DateTime?,但我需要有一些孩子的大師,只是少數幾個還沒有孩子。

解決方案#1添加where m.Childs.Count() > 0。 這一次踢我很難和意外,生成的SQL只是普通可怕(因爲是它的執行計劃),幾乎兩倍慢的跑:

SELECT [t2].[Name] AS [MasterName], [t2].[value] AS [cm] 
FROM (
    SELECT [t0].[id], [t0].[Name], (
     SELECT MAX([t1].[CreatedOn]) 
     FROM [Child] AS [t1] 
     WHERE [t1].[masterId] = [t0].[id] 
     ) AS [value] 
    FROM [Master] AS [t0] 
    ) AS [t2] 
WHERE ((
    SELECT COUNT(*) 
    FROM [Child] AS [t3] 
    WHERE [t3].[masterId] = [t2].[id] 
    )) > @p0 

解決方案#2where mc != null甚至最糟糕的,它給更短的劇本,但它執行遠遠比上面一個較長(需要大約同一時間,上述兩個一起)

SELECT [t2].[Name] AS [MasterName], [t2].[value] AS [cm] 
FROM (
    SELECT [t0].[id], [t0].[Name], (
     SELECT MAX([t1].[CreatedOn]) 
     FROM [Child] AS [t1] 
     WHERE [t1].[masterId] = [t0].[id] 
     ) AS [value] 
    FROM [Master] AS [t0] 
    ) AS [t2] 
WHERE ([t2].[value]) IS NOT NULL 

總而言之耽誤了不少SQL時間,以消除從幾十個或數千個或幾行更多。這使我解決方案#3,得到的一切,消除空的客戶端,但要做到這一點,我不得不親吻的IQueryable再見:

var masters = from m in Master 
       let mc = (DateTime?)m.Childs.Max(c => c.CreatedOn) 
       select new { m, mc }; 
var mastersNotNull = masters.AsEnumerable().Where(m => m.mc != null); 

和工作的,但是我想,如果弄清楚那裏這有什麼缺點?無論如何,這將完全不同於完整的monty IQueryable嗎?我想這也意味着我不能(或不應該)使用主人作爲不同的IQueryable中的因素?任何意見/觀察/選擇都是可以接受的。

回答

0

正是基於這一要求:

一個主表和鏈接兒童 表(一個主,很多孩子)。 比方說,我們要提取所有 大師和他們的首要時間 孩子值

SELECT [m].[Name] AS [MasterName] 
    , Max([c].[value]) as [cm] 
FROM [Master] AS [m] 
left outer join [Child] as [c] on m.id = c.id 
group by [m].[name] 
+0

好吧,我知道如何讓我從T-SQL想,我希望留在事物的LINQ側所以我可以直接利用這一發展模式。 – mmix

+0

http://bhaidar.net/post/2007/08/01/LEFT-OUTER-JOIN-in-LINQ-To-SQL.aspx – JeffO

+0

那麼,至少你試圖貢獻,所以我會接受你的答案。 – mmix