天天看點

一起談.NET技術,Linq To SQL 批量更新方法彙總

地球人都知道的,也是不少 Linq To SQL 反對者認為效率低下的一種方法。

這種方法必須要查詢出要更新的資料,确實有點不雅,也是Linq To SQL 略顯尴尬的一面。

方法二、使用ExpressionVisitor擷取Lambda表達式生成的SQL條件語句

方法原型:

實作原理:擴充Table,解釋表達式樹成SQL語句。其中解釋表達式樹包括和更新表達式,後者相對容易處理,例如表達式:

c => new Customer { Address = "Guangzhou", ContactName = "CoolCode", CompanyName = "Microsoft" }

解釋成

Address = @Address, ContactName = @ContactName, CompanyName = @CompanyName

而相應的值("Guangzhou", "CoolCode",  "Microsoft" )作為SQL參數傳遞。

實作這一步,其實就是從表達式 Expression<Func> 中取到初始化的屬性名字和值就可以,具體做法可以使用Expression Tree Viewer來輔助,從下圖可以了解到 Expression<Func> 的樹形結構。

一起談.NET技術,Linq To SQL 批量更新方法彙總

然後我按上面的結構圖“照葫蘆畫瓢”就得到要更新的屬性名字和值:

而解釋where條件就相對沒這麼輕松了。

注:Jeffrey Zhao 的批量删除一文提供的源代碼中,ConditionBuilder 并不支援生成Like操作,如 字元串的 StartsWith,Contains,EndsWith 并不能生成這樣的SQL: Like ‘xxx%’, Like ‘%xxx%’ , Like ‘%xxx’ 。我通過分析 ExpressionVisitor ,也不難發現隻要override VisitMethodCall 這個方法即可實作上述功能。

<a href="http://11011.net/software/vspaste"></a>

到此刻,已經解決了解釋表達式樹的難題,那麼實作通過表達式樹生成完整的 Update SQL語句這個設想也不是什麼難事了。

例如上面提到的示例所生成的 Updae SQL語句是:

UPDATE dbo.Customers SET [Address]={1}, [ContactName]={2}, [CompanyName]={3} WHERE ([CustomerID] = {0})

相應參數:"Bruce", "Guangzhou", "CoolCode",  "Microsoft"

據不完全統計,實際開發中用的 Update SQL 90%是很簡單的,以上擴充基本上符合要求。

方法三、使用 LinqToSQL 自身的解析器來擷取Lambda表達式生成的SQL條件語句

該方法與方法二基本上是同一思路,隻是在擷取Lambda表達式生成的SQL條件上有點不一樣。

通過 DataContext 的 GetCommand 可以擷取到 DbCommand,是以通過生成的SQL查詢語句中截取Where後面的條件,再用方法二生成Update 的指派語句,兩者拼湊起來即可。

一起談.NET技術,Linq To SQL 批量更新方法彙總

該方法比方法二支援更多Lambda表達式(實際上就是所有LinqToSQL支援的)生成SQL條件。

同樣使用文章開頭的示例,生成的 Update SQL 跟方法二略有不同:

UPDATE dbo.Customers SET [Address]=@Address, [ContactName]=@ContactName, [CompanyName]=@CompanyName FROM dbo.Customers AS t0 WHERE [t0].[CustomerID] = @p0

要知道,前面提到的方法二和三都不支援多表關聯的複雜條件。可以用一個示例讓大家更清楚為什麼——

例如,更新CustomerID=“Bruce”的使用者的所有訂單的送貨日前是一個月後。

應該生成的 Update SQL 語句是:

但遺憾的是無論用方法二或三都會抛異常,因為兩者皆沒法解釋多表關聯生成的語句: “LEFT OUTER JOIN [dbo].[Customers] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID] ”

雖然跟我剛才手寫的SQL略有不同,但 Update 的邏輯是對的。有興趣的朋友不妨試試,Terry Aney在他的文章裡有很詳盡的介紹,這裡不再詳述。

相關博文:

<a href="http://www.aneyfamily.com/terryandann/post/2008/04/Batch-Updates-and-Deletes-with-LINQ-to-SQL.aspx">Batch Updates and Deletes with LINQ to SQL</a>

<a href="http://www.aneyfamily.com/terryandann/post/2008/04/LINQ-to-SQL-Batch-UpdatesDeletes-Fix-for-Could-not-translate-expression.aspx">LINQ to SQL Batch Updates/Deletes: Fix for 'Could not translate expression'</a>

<a href="http://www.aneyfamily.com/terryandann/post/2008/12/Ive-Left-Query-Analyzer-Hell-For-LINQPad-Heaven.aspx">I've Left Query Analyzer Hell For LINQPad Heaven</a>

Linq To SQL 有很多地方值得探索的,Expression Tree 是探索的基礎, 嘿嘿!

完整代碼(内含Terry Aney 的代碼)

<a href="http://files.cnblogs.com/coolcode/Linq2SQL%E6%89%B9%E9%87%8F%E6%9B%B4%E6%96%B0.rar">Linq2SQL批量更新.rar</a>