转载:LINQ to SQL更新数据库操作
????? 翻譯整理ScottGu的關(guān)于LINQ to SQL的Part 4: Updating our Database 。該Post講解了如何使用LINQ to SQL更新數(shù)據(jù)庫,以及如何整合業(yè)務(wù)邏輯和自定義驗證邏輯。開發(fā)環(huán)境為.NET Framework 3.5 Beta2,開發(fā)工具為Visual Studio 2008 Beta2。?
????? 使用LINQ to SQL建模Northwind數(shù)據(jù)庫
在這之前一起學過LINQ to SQL設(shè)計器的使用,下面就使用如下的數(shù)據(jù)模型:
????? 當使用LINQ to SQL設(shè)計器設(shè)計以上定義的五個類(Product,Category,Customer,Order和OrderDetail)的時候,每個類中的屬性都映射了相應(yīng)數(shù)據(jù)庫中表的列,每個類的實例則代表了數(shù)據(jù)庫表中的一條記錄。另外,當定義數(shù)據(jù)模型時,LINQ to SQL設(shè)計器同樣會創(chuàng)建一個自定義DataContext類,來作為數(shù)據(jù)庫查詢和應(yīng)用更新/變化的主要渠道。以上數(shù)據(jù)模型中定義的DataContext類命名為“NorthwindDataContext”。該類中包含了代表每個建模數(shù)據(jù)庫表的屬性。
????? 使用LINQ語法表達式可以十分簡單的使用NorthwindDataContext類來查詢和檢索數(shù)據(jù)庫中的數(shù)據(jù)。LINQ to SQL會在運行時自動的轉(zhuǎn)換LINQ表達式到適當?shù)腟QL代碼來執(zhí)行。例如,編寫以下LINQ表達式來根據(jù)Product Name檢索單個Product對象:
???? 還可以使用LINQ表達式來檢索所有不存在于Order Details中的,并且UnitPrice大于100的所以Product:
???? 變化跟蹤和DataContext.SubmitChanges()
???? 當執(zhí)行查詢和檢索像Product實例這樣的對象時,LINQ to SQL會自動保持對這些對象任何變化或更新的跟蹤。我們可以進行任意次數(shù)的查詢,以及使用LINQ to SQL的DataContext類作出更新,而這些變化都會被全部跟蹤。
注意:LINQ to SQL的變化跟蹤發(fā)生于調(diào)用者端——而不是在數(shù)據(jù)庫中。這就意味著使用跟蹤不會銷耗任何數(shù)據(jù)庫資源,也不需要在數(shù)據(jù)庫中改變/安裝任何組件模塊。
當對從LINQ to SQL中檢索的對象作出更改之后,我們可以選擇調(diào)用DataContext上的SubmitChange()方法來應(yīng)用變化返回到數(shù)據(jù)庫。這將會導(dǎo)致LINQ to SQL動態(tài)計算并執(zhí)行適當?shù)腟QL代碼來更新數(shù)據(jù)庫。例如,編寫以下代碼更新數(shù)據(jù)庫中Product Name為“Chai”的Product上的UnitPrice和UnitsInStock:
當在以上代碼中調(diào)用northwind.SubmitChanges()方法時,LINQ to SQL會動態(tài)構(gòu)建并執(zhí)行一個更新這兩個Product屬性值的SQL“UPDATE”代碼模塊。
在下面代碼中我們來遍歷不流行的,昂貴的Product,并把它們的ReorderLevel屬性設(shè)為0:
當在以上代碼中調(diào)用northwind.SubmitChanges()方法時,LINQ to SQL會計算并執(zhí)行一組適當?shù)腢PDATE代碼模塊來修改RecorderLevel屬性已變化的Product。
注意,如果一個Product的屬性沒有通過屬性指定而發(fā)生變化,則該對象不會被認為是發(fā)生變化的,并且LINQ to SQL也不會對于該對象執(zhí)行更新回數(shù)據(jù)庫的操作。例如,如果“Chai”對象的UnitPrice仍舊是$2,UnitsInStock仍舊是4,當調(diào)用SubmitChange()時不會導(dǎo)致任何數(shù)據(jù)庫UPDATE代碼模塊的執(zhí)行。相似的,在第二個例子中的那些符合條件的Product中只有RecorderLevel原來不是0的才會在SubmitChange()被調(diào)用時更新。
插入和刪除示例
除了更新數(shù)據(jù)庫中已存在的行之外,LINQ to SQL同樣支持插入和刪除數(shù)據(jù)。可以通過從DataContext的表集合中添加/移除數(shù)據(jù)對象,并調(diào)用SubmitChange()方法來實現(xiàn)數(shù)據(jù)庫中的插入和刪除操作。LINQ to SQL也會對添加/移除操作保持跟蹤,并當SubmitChange()被調(diào)用時自動執(zhí)行適當?shù)腟QL中的INSERT或DELETE代碼模塊。
插入Product
可以通過創(chuàng)建一個新Product實例添加一個新的Product到數(shù)據(jù)庫,設(shè)置它的屬性,并添加它到DataContext類中的Product集合中:
當在以上代碼中調(diào)用northwind.SubmitChanges()方法時,在數(shù)據(jù)庫的Product表中會有一條新的記錄被創(chuàng)建。
刪除Product
與添加相似,可以通過從DataContext類中的Product集合中移除某一產(chǎn)品來表達想要從數(shù)據(jù)庫中刪除相應(yīng)的記錄:
在以上代碼中先使用LINQ查詢檢索一系列不會被訂購的Product,然后將其傳入DataContext類中Product集合上的RemoveAll()方法。當在以上代碼中調(diào)用northwind.SubmitChanges()方法時,這些Product記錄就會從數(shù)據(jù)庫中的Product表中刪除。
通過關(guān)系關(guān)聯(lián)更新
像LINQ to SQL這樣十分靈活的O/R映射工具,可以讓我們很簡單的通過表之間的關(guān)系關(guān)聯(lián)來對數(shù)據(jù)模型建模。例如,可以把每個Product建模到一個Category中,每個Order包含多條OrderDetail明細,每條OrderDetail明細都關(guān)聯(lián)著一個Product,并且每個Customer擁有一組相關(guān)聯(lián)的Order。
LINQ to SQL能夠讓我們不論是在查詢還是更新數(shù)據(jù)中都可以利用這些關(guān)系關(guān)聯(lián)。例如,編寫以下代碼來創(chuàng)建一個新Product,并關(guān)聯(lián)到一個數(shù)據(jù)庫中已存在的“Beverages”Category上:
注意如何添加Product對象到該Category的Product集合中。這樣就會指明這兩個對象之間存在關(guān)系關(guān)聯(lián),并會導(dǎo)致LINQ to SQL在調(diào)用SubmitChange()時,自動維護兩者之間的主/外鍵關(guān)系關(guān)聯(lián)。
另一個LINQ to SQL有助于管理交叉表關(guān)系關(guān)聯(lián)的例子,讓我們看一下如何對一個現(xiàn)有的Customer創(chuàng)建一個新的Order。在設(shè)置Order的OrderDate和RequireDate和Freight后,然后創(chuàng)建兩個Customer訂購的Product相關(guān)的OrderDetail,并添加到Order中,隨后關(guān)聯(lián)Order到Customer上,最后更新所有變化回數(shù)據(jù)庫:
正如所看到,執(zhí)行所以這些工作的編程模型是十分清晰并且是面向?qū)ο蟮摹?/p>
事務(wù)
事務(wù)是一種通過數(shù)據(jù)庫(或其他資源管理器)提供的服務(wù),來保證了一系列的單獨的操作是原子性發(fā)生的——這就意味著它們要么全部成功,要么全部失敗,并且當這一系列操作都自動執(zhí)行完畢之前,不會有任何更改會發(fā)生。當調(diào)用DataContext上的SumbitChange()方法時,這些更新操作會包裝到一個事務(wù)中。這就意味著當執(zhí)行多個變化更新時,數(shù)據(jù)庫永遠不會陷入不一致的狀態(tài)——這些變化要么一起被保存,要么任何變化都不保存。
驗證和業(yè)務(wù)邏輯
對于處理數(shù)據(jù),開發(fā)需要考慮的一件十分重要的事就是如何融合數(shù)據(jù)驗證和業(yè)務(wù)規(guī)則邏輯。LINQ to SQL為開發(fā)者提供了多種途徑,可以十分簡潔地把這些整合到數(shù)據(jù)模型中。LINQ to SQL會確保一旦添加數(shù)據(jù)驗證邏輯,就可以無論何時何地在都應(yīng)用于數(shù)據(jù)模型上。這就避免了在多處的重復(fù)定義,保證了數(shù)據(jù)模型的可維護性和代碼整潔。
構(gòu)架驗證支持
當在Visual Studio 2008中使用LINQ to SQL設(shè)計器定義數(shù)據(jù)模型類時,會被默認附加一些根據(jù)數(shù)據(jù)庫表構(gòu)架推斷出的驗證規(guī)則。數(shù)據(jù)模型類中的屬性的數(shù)據(jù)類型會與數(shù)據(jù)庫構(gòu)架的數(shù)據(jù)類型相匹配。這就意味著如果試圖指定一個boolean值到decimal,或試圖隱式轉(zhuǎn)換numeric類型都會導(dǎo)致編譯錯誤。如果數(shù)據(jù)庫中的列可以為null,則通過LINQ to SQL設(shè)計器創(chuàng)建的在數(shù)據(jù)模型中的相應(yīng)的屬性會是一個Nullable類型。如果試圖給未標記為Nullable的屬性指定null值,會自動引發(fā)異常。相似地,LINQ to SQL也會確保數(shù)據(jù)庫中的identity/unique列值的正確驗證。
當然也可以使用LINQ to SQL設(shè)計器來覆寫這些默認的構(gòu)架驅(qū)動的驗證設(shè)置——但是通過默認我們可以自動獲得它們,而且不需要進行額外的工作。LINQ to SQL同樣會自動處理轉(zhuǎn)義的SQL值,這樣就不必擔心SQL注入攻擊了。
自定義屬性驗證支持
構(gòu)架驅(qū)動的數(shù)據(jù)驗證僅僅是應(yīng)用的第一步,但對于實際應(yīng)用來說還是不夠的。考慮Northwind中的一種情況——Customer類上的Phone屬性,在數(shù)據(jù)庫中被定義為NVARCHAR類型。開發(fā)者可以使用LINQ to SQL編寫如下代碼更新一個有效的電話號碼:
?
但在應(yīng)用中會碰到這樣的疑問,如對于下面的代碼,從單純的SQL構(gòu)架方面來說是合法的:
為防止虛假的電話號碼被添加進數(shù)據(jù)庫,我們可以添加一個自定義屬性驗證規(guī)則到Customer數(shù)據(jù)模型類中。使用局部類的特性,可以十分簡單的添加規(guī)則來驗證電話號碼,只需要添加一個新的包含如下方法定義的局部類到我們的項目中:
?
以上代碼利用了LINQ to SQL的兩個特性:
1.所以通過LINQ to SQL設(shè)計器創(chuàng)建的類都被聲明為局部類——這就意味著開發(fā)者可以十分方便地為這些類添加額外的方法,屬性和事件。這樣對通過LINQ to SQL設(shè)計器創(chuàng)建的數(shù)據(jù)模型類和DataContext類,可以很簡單的擴充自已定義驗證規(guī)則和額外的自定義輔助方法。沒有任何設(shè)置或后續(xù)代碼要求。
2.LINQ to SQL會在數(shù)據(jù)模型類和DataContext類中暴露了一些自定義的可擴展點,用來在事件發(fā)生之前和之后添加驗證邏輯。其中許多的擴展點利用了稱為“partial methods(局部方法)”的新語言特性。
在上面的驗證示例中,我們使用了在任何設(shè)置Customer類上Phone屬性時都會被執(zhí)行的OnPhoneChanging方法。使用該方法來驗證輸入,如果驗證成功,則從該方法中返回并且LINQ to SQL會認定該值是有效的,否則就會在該驗證方法中產(chǎn)生一個異常——防止發(fā)生賦值操作。
自定義實體對象驗證支持
屬性級別的驗證對于驗證數(shù)據(jù)模型類上獨立的屬性是十分有效的。但有時卻需要同時驗證一個對象上的多個屬性。考慮這樣一個場景,同時設(shè)置Order對象上的OrderDate和RequiredDate屬性:
以上的代碼從單純的SQL構(gòu)架方面來說是合法的——即使規(guī)定交貨日期是訂單下達日期的前一天是毫無意義的。好消息是現(xiàn)在在Beta2(.NET Framework 3.5)中LINQ to SQL可以十分簡單地添加自定義實體級別的驗證規(guī)則來防止類似的錯誤發(fā)生。可以為Order實體類添加一個局部類,并實現(xiàn)OnValidate()局部方法,該方法會在實體的值將要記錄進數(shù)據(jù)庫的時候被調(diào)用。使用該驗證方法可以訪問和驗證所有的數(shù)據(jù)模型類屬性:
?
使用該驗證方法我們可以檢查實體類上的任何屬性值(即使對于它的管理對象只獲得只讀訪問),如果驗證的值不正確就可以產(chǎn)生一個異常。從OnValidate()方法中產(chǎn)生的任何異常都導(dǎo)致從數(shù)據(jù)庫更新操作中退出,并且回滾該操作所在事務(wù)中的所以更改。
自定義實體插入/更新/刪除方法驗證
在實際應(yīng)用中,有時我們會需要對于特定的插入,更新或刪除場景來添加驗證邏輯。在Beta2(.NET Framework 3.5)中LINQ to SQL可以通過添加局部類型來擴展DataContext類,然后實現(xiàn)相應(yīng)的局部方法來為數(shù)據(jù)模型實體自定義插入,更新和刪除邏輯。當調(diào)用DataContext類上的SubmitChanges()方法時,這些方法會被自動調(diào)用。
使用這些方法添加適當?shù)尿炞C邏輯后,如果驗證通過就會通知LINQ to SQL繼續(xù)進行數(shù)據(jù)庫更新操作(通過調(diào)用DataContext類中的“ExecuteDynamicXYZ”方法):
適當?shù)靥砑右陨戏椒ê?#xff0c;對于數(shù)據(jù)對象的任何創(chuàng)建/更新/刪除操作都會自動調(diào)用這些方法。例如,考慮這樣一個場景,創(chuàng)建一個新的Order并關(guān)聯(lián)到一個已存在的Customer上:
?
當在上面的示例代碼中調(diào)用northwind.SubmitChanges()時,LINQ to SQL會確認是否需要插入一個新的Order對象,并自動調(diào)用InsertOrder局部方法。
高級:為事務(wù)察看實體變化
在實際應(yīng)用中,有時不能單純地通過察看單獨的插入/更新/插入操作來添加驗證邏輯,而是應(yīng)察看一個以事務(wù)發(fā)生的實體操作變化列表。從.NET Framework 3.5 Beta2開始,我們可以通過調(diào)用公共的DataContext.GetChangeSet()方法來訪問這個變化列表。該方法會返回一個暴露每個已作出的添加,修改和移除操作的ChangeSet對象。
還有一種可供選擇的方式是編寫DataContext的子類并覆寫SubmitChanges()方法。然后就可以為更新操作檢索ChangeSet,并執(zhí)行任何自定義的數(shù)據(jù)驗證:
使用樂觀并發(fā)執(zhí)行處理同時發(fā)生的變化
在多用戶數(shù)據(jù)庫系統(tǒng)中開發(fā)者需要考慮的事情之一,就是如何處理對于數(shù)據(jù)庫中數(shù)據(jù)同時發(fā)生的更新。例如,假設(shè)兩個用戶在同一應(yīng)用程序中檢索同樣的Product對象,一個用戶更新RecorderLevel為0,而另一個更新為1。如果兩個用戶都要試圖保存Product的更新到數(shù)據(jù)庫,那么開發(fā)者就需要決定如何處理變化沖突。
一種方式是“讓后來的更新者獲勝”——這就意味者先來的用戶提交的值會在重大用戶沒有察覺的情況下丟失。這通常被認為是一種缺乏應(yīng)用程序開發(fā)經(jīng)驗的一種表現(xiàn)。
另一種而且是LINQ to SQL支持的方式是使用樂觀并發(fā)執(zhí)行模型——如何數(shù)據(jù)庫中的原始值已經(jīng)有其他更新操作事先要執(zhí)行,LINQ to SQL會自動檢測發(fā)生地點。LINQ to SQL可以提供一個更改值的沖突列表給開發(fā)者,并且能夠調(diào)和分歧,或者是通過UI通知應(yīng)用程序終端用戶來讓他們決定如何處理。
為插入/更新/刪除場景使用存儲過程或自定義SQL邏輯
對于數(shù)據(jù)庫開發(fā)者來說,好消息是LINQ to SQL提供了相當靈活的開發(fā)模型,可以讓開發(fā)者覆寫通過LINQ to SQL自動執(zhí)行的動態(tài)SQL,并替代為調(diào)用自定義的插入,更新,刪除用的存儲過程。
一開始的時候,我們可以定義數(shù)據(jù)模型并使用LINQ to SQL自動處理插入,更新,刪除等邏輯。在稍后還可以自定義用于更新數(shù)據(jù)模型的存儲過程或SQL——不需要對使用數(shù)據(jù)模型的應(yīng)用程序邏輯作出任何改變,也不需要對相應(yīng)的數(shù)據(jù)驗證或業(yè)務(wù)規(guī)則邏輯作出任何改變。這就為應(yīng)用程序的構(gòu)建提供了大量的靈活性。
總結(jié)
除了一般的插入,更新,刪除操作,以及數(shù)據(jù)驗證外,通過這篇Post我們還應(yīng)注意以下一些要點:
1.善于利用表之間的關(guān)系關(guān)聯(lián)進行數(shù)據(jù)更新
2.數(shù)據(jù)驗證和業(yè)務(wù)邏輯驗證的應(yīng)用級別包括:構(gòu)架級,實體級,屬性級,更新操作時驗證和以事務(wù)為單位的驗證
3.LINQ to SQL還可以有效地處理SQL注入攻擊
4.LINQ to SQL還可以自動處理事務(wù)
5.LINQ to SQL使用樂觀并發(fā)執(zhí)行模型處理更新沖突
?
注:
??? 原文地址:http://www.cnblogs.com/xuhy-developer/articles/849281.html
總結(jié)
以上是生活随笔為你收集整理的转载:LINQ to SQL更新数据库操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FPA笔记六 计算EI/EO/EQ的功能
- 下一篇: FC10的下载地址