本文接著上篇Linq to SQL之查詢和添加,還是以Northwind數據庫為例,介紹使用Linq to SQL怎樣對 數據庫的數據進行更新及沖突的相關問題。
首先對Customers表的一條記錄進行更新:
NorthwindDataContext ctx = new NorthwindDataContext();
Customer alfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
Console.WriteLine("Before update, the company name of Alfki is: " + alfki.CompanyName);
alfki.CompanyName = "New Company Name";
ctx.SubmitChanges();
Customer newAlfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
Console.WriteLine("After update, the company name of Alfki is: " + alfki.CompanyName);
通過屏幕輸出,可以看到數據的確已經更新成功了
Before update, the company name of Alfki is: Alfreds Futterkiste
After update, the company name of Alfki is: New Company Name
現在,把調用SubmitChanges方法放在最後,看看會發生什麼:
NorthwindDataContext ctx = new NorthwindDataContext();
Customer alfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
Console.WriteLine("Before update, the company name of Alfki is: " + alfki.CompanyName);
alfki.CompanyName = "New Company Name";
Customer newAlfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
Console.WriteLine("Before submit changes, the company name of Alfki is: " + alfki.CompanyName);
ctx.SubmitChanges();
屏幕的輸出為:
Before update, the company name of Alfki is: Alfreds Futterkiste
Before submit changes, the company name of Alfki is: New Company Name
可以看到,第二次查詢是在更新提交之前,這時候數據庫中的值還沒有改變,按理說這時候去進行數 據庫查詢得到的值應該還是舊值,但是代碼運行後發現查詢出來的值確是更新後的值。這是為什麼呢?其 實原因還是上篇提到過的Identity Cache,DataContext以主鍵為key對數據對象進行緩存以此對數據對象 的生命周期進行跟蹤。借助Sql profile可以發現,第二次調用ctx.Customers.Single時,數據庫並沒有 查詢的記錄,這裡DataContext直接在內存中查找該對象並且返回。當然也可以關閉這種機制,只需要調 用ctx.ObjectTrackingEnabled = false。DataContext就不再對數據對象進行Identity Cache,每次查詢 結果都是通過查詢數據庫得到。
數據庫數據更新通常會遇到同步沖突的問題,比如獲得數據以後,對數據進行一系列的操作,然後把 新的數據更新回數據庫。如果在數據進行操作的同時,有其它程序或者管理員改動了該數據的值,這樣就 會發生沖突。到底數據是應該保留現有的值呢還是把改動的值強行更新到數據庫呢?Linq to SQL提供了 很多方法來解決這種沖突問題。
還是一段簡單的更新代碼:
NorthwindDataContext ctx = new NorthwindDataContext();
Customer alfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
alfki.CompanyName = "New Company Name";
ctx.SubmitChanges();
在SubmitChanges()加上斷點然後運行,接著在數據庫管理器中修改這條記錄的CompanyName,最後回 到vs界面,繼續往下運行,這時會拋出ChangeConflictException,提示該行記錄已經被刪除或者被修改
在Linq to SQL中,解決沖突有幾種方法:
在映射字段的Column Attribute中添加UpdateCheck屬性
[Column(Storage="_CompanyName", DbType="NVarChar(40) NOT NULL", CanBeNull=false, UpdateCheck=UpdateCheck.Never)]
public string CompanyName {
UpdateCheck的意思是在更新的時候是否檢查沖突,分為三種,根據自己的需求進行選擇:
Always 始終檢查
Never 從不檢查
WhenChanged 當數據有改動的時候檢查
2. 使用ObjectChangeConflict的Resolve方法,比如:
try
{
ctx.SubmitChanges();
}
catch (ChangeConflictException)
{
foreach (ObjectChangeConflict confict in ctx.ChangeConflicts)
{
confict.Resolve(RefreshMode.KeepCurrentValues);
}
}
finally
{
ctx.SubmitChanges();
}
這裡RefreshMode就是表示解決沖突的方法,也有三種:
KeepChanges 把改變過的屬性值更新到數據庫,沒有改變過的屬性值就用數據庫的當前值
KeepCurrentValues 把當前所有值更新到數據庫
OverwriteCurrentValues 使用數據庫的當前值,不做強行更新