設置很簡單,主表和一個鏈接的子表(一個主,很多子)。比方說,我們想要提取所有的主人和他們的時間順序的兒童價值(更新,訪問等)。查詢應該是這樣的(例如):如果主人有沒有孩子發生限制結果集中的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
解決方案#2與where 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中的因素?任何意見/觀察/選擇都是可以接受的。
好吧,我知道如何讓我從T-SQL想,我希望留在事物的LINQ側所以我可以直接利用這一發展模式。 – mmix
http://bhaidar.net/post/2007/08/01/LEFT-OUTER-JOIN-in-LINQ-To-SQL.aspx – JeffO
那麼,至少你試圖貢獻,所以我會接受你的答案。 – mmix