在LINQ to SQL中使用Translate方法以及修改查詢用SQL
[2] 使用Translate方法1
[3] 使用Translate方法2
[4] 改變LINQ to SQL所執行的SQL語句
[5] 擴展所受的限制
目前LINQ to SQL的資料不多——老趙的意思是,目前能找到的資料都難以擺脫“官方用法”的“陰影”。LINQ to SQL最權威的資料自然是MSDN,但是MSDN中的文檔說明和實例總是顯得“大開大闔”,依舊有清晰的“官方”烙印——這簡直是一定的。不過從按照過往的經驗,在某些時候如果不按照微軟劃定的道道來走,可能就會發現別樣的風景。老趙在最近的項目中使用了LINQ to SQL作為數據層的基礎,在LINQ to SQL開發方面積累了一定經驗,也總結出了一些官方文檔上并未提及的有用做法,特此和大家分享。
言歸正傳,我們先看一個簡單的例子。
Item實體對應Item表,每個Item擁有一些評論,也就是ItemComment。Item實體中有一個Comments屬性,是ItemComment實體的集合。這個例子將會使用這個再簡單不過的模型。
為用戶顯示他的Item列表是非常常見的需求,如果使用LINQ to SQL來獲取Item的話,我們可能會這么做:
public List<Item> GetItemsForListing(int ownerId) { ItemDataContext dataContext = new ItemDataContext(); var query = from item in dataContext.Items where item.UserID == ownerId orderby item.CreateTime descending select item; return query.ToList(); }
這么做自然可以實現我們想要的功能,這的確沒錯。但是這種做法有個很常見的問題,那就是可能會獲得太多不需要的數據。一個Item數據量最大的是Introduction字段,而顯示列表的時候我們是不需要顯示它的。如果我們在獲取Item列表時把Introduction一起獲得的話,那么應用服務器和數據庫服務器之間的數據通信量將會成百甚至上千地增長了。因此我們在面向此類需求的話,都會忽略每個Item對象的Introduction字段。那么我們該怎么做呢?對LINQ有簡單了解的朋友們可能會想到這么做:
public List<Item> GetItemsForListing(int ownerId) { ItemDataContext dataContext = new ItemDataContext(); var query = from item in dataContext.Items where item.UserID == ownerId orderby item.CreateTime descending select new Item { ItemID = item.ItemID, Title = item.Title, UserID = item.UserID, CreateTime = item.CreateTime }; return query.ToList(); }
這個做法很直觀,利用了C# 3.0中的Object Initializer特性。編譯通過了,理應沒有錯,可是在運行時卻拋出了NotSupportedException:“Explicit construction of entity type 'Demo.Item' in query is not allowed.”,意思就是不能在LINQ to SQL中顯式構造Demo.Item對象。
事實上在RTM之前的版本中,以上的語句是能運行通過的——我是指通過,不是正確。LINQ to SQL在RTM之前的版本有個Bug,如果在查詢中顯式構造一個實體的話,在某些情況下會得到一系列完全相同的對象。很可惜這個Bug我只在資料中看到過,而在RTM版本的LINQ to SQL中這個Bug已經被修補了,確切地說是繞過了。直接拋出異常不失為一種“解決問題”的辦法,雖然這實際上是去除了一個功能——沒有功能自然不會有Bug,就像沒有頭就不會頭痛了一個道理。
但是我們還得做,難道我們只能自己SQL語句了嗎?