本文將通過場景例子演示,來通俗易懂的講解在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼。 通過一系列優化最終達到兩個效果,1.通過代碼塊來控制事務(分散式事務),2.通過委托優化TransactionScope的編碼寫法。 本文需要的知識點:1. Action委托 2. 分散式事務Tr ...
本文將通過場景例子演示,來通俗易懂的講解在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼。
通過一系列優化最終達到兩個效果,1.通過代碼塊來控制事務(分散式事務),2.通過委托優化TransactionScope的編碼寫法。
本文需要的知識點:1. Action委托 2. 分散式事務TransactionScope(不懂不要緊,文中會講解)
----------------------
.Net高級進階,教你如何構建企業模型數據攔截層,動態控制欄位驗證
.Net高級進階,在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼?
web安全:通俗易懂,以實例講述破解網站的原理及如何進行防護!如何讓網站變得更安全。
.Net,Dll掃盲篇,如何在VS中調試已經編譯好的dll?
----------------------
示例一和示例二,主要是來講解 TransactionScope 是什麼,為什麼要用TransactionScope。
示例三(重要)則是優化寫法,增加代碼的靈活性和可讀性。
【示例一】
現在,你要寫個入庫介面,大致意思就是: 勾選一條商品,然後寫上數量,點擊入庫按鈕,將會產生一條入庫記錄,同時 這個商品的所對應的 庫存數量 也會 更新。
因為涉及到庫存,所以要用事務來保證數據安全。
StorageTask:入庫作業表,存寫入庫記錄
GoodsInventory:商品庫存表, 裡面放的是 不同商品的 詳細介紹、數量等信息
那麼我們的實現 , 可能是 這樣的 , 如圖:
上圖的代碼,我們主要是先看 商品入庫操作 GoodsInventoryOperate 這個Dal方法,放圖:
上面的這是一個Dal方法,事務寫法很大眾,很常規,代碼沒毛病。
【示例二】
好,現在,我們的業務要求要改一下,改成這樣的:
勾選了一條商品,輸入該條商品的入庫數量,然後又勾選了一條原材料,輸入該原材料的入庫數量,最終點擊入庫按鈕,要 產生 商品的入庫記錄和原材料的入庫記錄, 還要 分別修改 所對應的 商品庫存表和原材料庫存表 的 庫存數量
那麼,我們就要修改下這個介面,首先,參數由原來的 單行的參數 改為 集合形式的 參數,
那麼我們的介面代碼也隨之修改,如下圖:
然後我們在看看 這個入庫操作方法 InventoryOperate
我們來對比下,我們把之前的 商品入庫操作 GoodsInventoryOperate 方法 給改成了 入庫操作方法 InventoryOperate 。
實際上,入庫操作方法 InventoryOperate = 商品入庫操作 + 原材料入庫操作 ,但是因為 業務的更改,讓我們不得不把 原本 Dal層中的兩個方法代碼 給 複製粘貼到一起,形成第三個方法,也就是入庫操作方法 InventoryOperate 。
那麼,有沒有一種寫法,能讓我們 更簡單更方便 不用每次複製粘貼代碼形式 來實現 事務的編寫?
有!
TransactionScope:
在早期.net時代,如果想使用事務,就用SqlTransaction來實現,而每個SqlTransaction都會用同一個SqlConnection連接對象。
如果邏輯簡單還好說,如果邏輯稍微複雜的話,想用多個Dal方法來共同組合一個事務的話,就非常費腦筋的,就像上文這樣演變的 第一版 和 第二版。
為此,在.Net2.0時代,TransactionScope誕生了,微軟官方描述:代碼塊事務,還有一個別稱:分散式事務。
它實現了IDisposable介面,可以把它被實例化開始到被Dispose掉之間的代碼作為一個事務,也就是它的存在,最終讓你的代碼塊所嵌套在其中多個DAL方法變成“一個方法”
那麼,當我們使用它以後,我們就可以這樣編寫:
【示例三】
現在,大家對 TransactionScope 有了基本的印象,那麼現在考慮到代碼的可讀性和靈活性,我將要對當前風格再次改寫,通過委托的形式讓代碼結構層次更加分明。
1 /// <summary> 2 /// 事務語句統一執行 3 /// </summary> 4 /// <param name="ac">委托</param> 5 /// <returns></returns> 6 public static bool TransactionExecute(Action ac) 7 { 8 try 9 { 10 using (TransactionScope ts = new TransactionScope()) 11 { 12 ac.Invoke(); 13 ts.Complete(); 14 } 15 return true; 16 } 17 catch 18 { 19 return false; 20 } 21 }
然後,我們的介面方法的編碼變成了這樣:
1 /// <summary> 2 /// 商品倉庫的入庫作業操作 3 /// </summary> 4 /// <param name="iData">入庫數據集合</param> 5 /// <returns></returns> 6 public string WarehouseGoodsOperate(List<InboundModel> iData) 7 { 8 Action ac = () => { };//聲明一個委托 9 foreach (InboundModel item in iData) 10 { 11 if (item.type == "商品") 12 { 13 ac += () => 14 { 15 IServices.Insert(item); 16 IServices.UpdateGoods(item); 17 }; 18 } 19 if (item.type == "原材料") 20 { 21 ac += () => 22 { 23 IServices.Insert(item); 24 IServices.UpdateInventory(item); 25 }; 26 } 27 } 28 if (IServices.TransactionExecute(ac)) 29 { 30 return "成功"; 31 } 32 return "失敗"; 33 }
通過上面這樣的寫法,最終讓代碼風格更乾凈,同時在 事務的 處理上更靈活方便, 我們只需要把想要執行的 方法 讓 ac 給包進去, 最後在調用 TransactionExecute 統一執行。
基於自己的場景可以定製自己的TransactionExecute,本文著重指出利用委托來優化該情況下的編碼思想,至於TransactionExecute,這裡只是做個簡單的科普,其中有更多可挖掘的地方,感興趣的童鞋可以自行百度。
當然,採用這種委托寫法,需要註意一點:
因為 類 是 引用類型 ,傳遞的地址和值類型不同, 所以最終你的委托執行的是 你最後對實例的更改, 所以你認為的能行,實際上是不能行。
那麼,怎樣解決這樣情況?
逐個逐個的賦值,或者用反射?
不用,我們可以通過繼承 ICloneable 介面,然後通過淺複製的方式實現Clone方法。
class SysUser : ICloneable { public object Clone() { return this.MemberwiseClone(); } }
最後,我們就可以這樣:
讓正確的程式更快比讓快速的程式正確要容易的多
我喜歡和我一樣的人交朋友,不被環境影響,自己是自己的老師,歡迎加群 .Net web交流群, QQ群:166843154 欲望與掙扎
作者:小曾
出處:http://www.cnblogs.com/1996V/p/7798111.html 歡迎轉載,但任何轉載必須保留完整文章,在顯要地方顯示署名以及原文鏈接。如您有任何疑問或者授權方面的協商,請給我留言
.Net交流群, QQ群:166843154 欲望與掙扎