.Net高級進階,在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼?

本文將經過場景例子演示,來通俗易懂的講解在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼。html

用一句話貫穿全文就是:經過委託來讓TransactionScope的編碼實現更直觀,並非講述TransactionScope的其它如分佈式、ACID等場景應用及解決方案。web

經過一系列優化最終達到兩個效果,1.讓不瞭解TransactionScope的童鞋經過代碼塊TransactionScope來控制事務,2.讓瞭解TransactionScope的童鞋簡單概述本實例的委託思想拋磚引玉來優化TransactionScope的編碼寫法。安全

本文須要的知識點:1. Action委託  2. 分佈式事務TransactionScope(不懂沒關係,文中會經過示例一和示例二簡單講解這是啥,爲啥要用)閉包

 

----------------------分佈式

 .Net Web開發技術棧web安全

.Net高級進階,教你如何構建企業模型數據攔截層,動態控制字段驗證post

.Net高級進階,在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼?優化

web安全:通俗易懂,以實例講述破解網站的原理及如何進行防禦!如何讓網站變得更安全。網站

web安全:QQ號快速登陸漏洞及被盜原理this

.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,這裏只是作個簡單的科普,其中有更多可挖掘的地方,感興趣的童鞋能夠自行百度。

 固然,採用這種委託寫法,須要注意一點:

 

由於傳遞的是引用,而且用用到了lambda,致使了閉包,最終在Invoke時在匿名類中會用同一引用。

那麼,怎樣解決這樣狀況?
逐個逐個的賦值,或者用反射?
不用,咱們能夠經過繼承 ICloneable 接口,而後經過淺複製的方式實現Clone方法(淺複製拷貝時,string會建立新的實例,若是尚有除string以外的引用類型還需深拷貝)。

    class SysUser : ICloneable
    {
        public object Clone()
        {
            return this.MemberwiseClone(); 
        }
    }

最後,咱們就能夠這樣:

 

讓正確的程序更快比讓快速的程序正確要容易的多

 

我喜歡和我同樣的人交朋友,不被環境影響,本身是本身的老師,歡迎加羣 .Net web交流羣, QQ羣:166843154 慾望與掙扎

 

做者:小曾
出處:http://www.cnblogs.com/1996V/p/7798111.html  歡迎轉載,但任何轉載必須保留完整文章,在顯要地方顯示署名以及原文連接。如您有任何疑問或者受權方面的協商,請給我留言
.Net交流羣, QQ羣:166843154 慾望與掙扎 
相關文章
相關標籤/搜索