從LINQ to SQL的"一行更新法"聊起
4 |
我喜歡LINQ to SQL的簡潔,就拿更新資料庫某筆資料這件事來說,你可以忘記SqlConnection、丟掉SqlCommand、抛下SqlParameter,就搞定整個更新動作,對寫慣ADO.NET的人來說,實在是件不可思議的事。
像下面這個例子,寫一段LINQ配上Single()取得資料物件,重新指定值,然後SubmitChanges()就完成了ID=2 Player資料的CreateTime欄位更新。有種袖子都還沒捲起來,敵人就忽然自已暴斃的莫名爽快。
protected void Page_Load(object sender, EventArgs e)
{
PlaygroundDataClassesDataContext db =
new PlaygroundDataClassesDataContext();
db.Log = new DebuggerWriter();
(from o in db.Players where o.ID == 2 select o)
.Single().CreateTime = DateTime.Now;
db.SubmitChanges();
}
上回既然提過DebuggerWriter,我們就不該只知其然不知其所以然,來看看背後發生什麼事吧!
這裡發生了兩個SQL動作,在Single()時會SELECT取回ID=2的資料,而SubmitChages()則進行UPDATE動作。值得一提的是,在UPDATE時,除了ID=2,它還會一併比較Name及CreateTime,用意是確認資料讀出到更新這段期間資料沒有被其他人更動過,防止多人同時更新資料庫時發生彼此資料互相覆寫衝突。
要印證它的保護效果,我們可以在db.SubmitChanges()上設定中斷點,讓VS2008跑偵錯模式停在該中斷點上,此時另外開SQL Server Management Studio執行T-SQL更新ID=2的資料:
UPDATE Player SET CreateTime = '2009-07-08 12:34:56'
WHERE ID = 2
接著好戲上場,在VS2008按下F10執行db.SubmitChanges(),會發生以下例外:
System.Data.Linq.ChangeConflictException: Row not found or changed. (中文版為: 資料列找不到,或者已變更。)
這個實驗證實了LINQ to SQL的確有提供資料庫更新時的衝突管理,然而要如何妥善處理更新衝突是門學問,保哥有篇文章做了進一步的剖析,推薦給大家參考。
當然,如果效能不是最優先考量,我還有一招。以前介紹過可在LINQ to SQL上使用的TransactionScope大法,在Single()到SubmitChanges()間對資料上鎖,防止別人擅動,就不會有衝突的問題(但想其他要更新資料的人會被卡住,直到這一方的UPDATE完成為止)。在此還是要善盡提醒之責,包TransactionScope的方法較適合更新頻率不高、鎖定時間不長、使用人數不多的情境,採用前宜審慎評估,不然有可能大幅拖累系統整體效能。
protected void Page_Load(object sender, EventArgs e)
{
using (System.Transactions.TransactionScope tx
= new System.Transactions.TransactionScope())
{
PlaygroundDataClassesDataContext db =
new PlaygroundDataClassesDataContext();
db.Log = new DebuggerWriter();
(from o in db.Players where o.ID == 2 select o)
.Single().CreateTime = DateTime.Now;
db.SubmitChanges();
}
}
Comments
# by Ho.Chun
請問一下,我上網查到一些資訊 LINQ to SQL 是在 .net framework 3.5 推出 (它只能處理 SQL Server) Entity Framework 也是在 .net framework 3.5 推出 (它不只能處理 SQL Server) 那麼在當時 LINQ to SQL 的優勢在哪邊呢 ? 感覺 LINQ to SQL 做的到的事情,Entity Framework 也一樣可以 (甚至更多)
# by Jeffrey
to Ho.Chun, LINQ to SQL 出現的時間比 EF 早一些,後來已被 EF 取代,除非是維護舊專案,選 EF 就對了。
# by Ho.Chun
想再請問一下 LINQ to SQL / Entity Framework / Entity Framework Core / Dapper / Linq2DB 這些常用於存取資料庫的技術,其底層皆使用 ADO.NET 嗎 ?
# by Jeffrey
to Ho.Chun, 凡用到 System.Data.IDbConnection 都算依賴 ADO.NET,EF Core 改用 Microsoft.Data.*,不包含在內。