<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      應用程序框架實戰三十四:數據傳輸對象(DTO)介紹及各類型實體比較

        本文將介紹DDD分層架構中廣泛使用的數據傳輸對象Dto,并且與領域實體Entity,查詢實體QueryObject,視圖實體ViewModel等幾種實體進行比較。

      領域實體為何不能一統江湖?

        當你閱讀我或其它博主提供的示例代碼時,會發現幾種類型的實體,這幾種實體初步看上去區別不大,只是名稱不同,特別在這些示例非常簡單的情況下更是如此。你可能會疑惑為何要搞得這么復雜,采用一種實體不是更好?

        在最理想的情況下,我們只想采用領域實體Entity進行所有的操作。

        領域實體是領域層的核心,是業務邏輯的主要放置場所。換句話說,領域實體中包含了大量業務邏輯方法。

      領域實體在表現層進行模型綁定時可能遇到障礙

        如果領域實體中的屬性都包含getter和setter,并且所有屬性都是public的,那么,使用這個Entity的程序員可能會繞過業務方法,直接操作屬性進行賦值。

        為屬性直接賦值,是面向數據的過程式思維,而調用方法是面向對象的方式,這也是領域模型的核心所在。

        所以為了強制實施業務規則,必須把業務方法操作過的屬性的setter訪問器隱藏起來,否則這個方法不會有人調用。

        當領域實體某些屬性的setter被隱藏后,直接在表現層操作領域實體將變得困難,因為Mvc或Wpf的模型綁定只能操作public的屬性。

      序列化領域實體可能遇到障礙

        哪怕你的系統沒有使用分布式,比如只是一個Mvc網站,但由于前端要求越來越高,客戶端很多時候需要通過ajax與服務端進行交流,一般采用json格式傳遞數據,這就要求你的實體能夠序列化。

        對領域實體進行序列化,首先需要考慮的問題是,可能序列化一個較大的對象圖,從而導致不必要的開銷。

        領域實體一般包含導航屬性指向其它領域實體,其它的領域實體可能包含更多導航屬性,從而組成一個對象圖。如果采用Serializable特性進行序列化,并且沒有指定其它序列化選項,可能導致把一個龐大的對象圖序列化并進行網絡傳輸。

        另一個問題是,復雜的領域實體可能包含循環引用,從而導致序列化失敗。

        對于序列化,一個更好的選擇是采用DataContract特性,被DataContract修飾過的類成員,不會被自動序列化,必須在成員上明確指定DataMember特性。

        DataMember在一定程度上可以緩解上述問題,比如減少需要序列化的數據,不序列化循環引用的對象等,但無法從根本上解決問題。

      領域實體無法應對多客戶端應用需求

        對于不同的客戶端,可能需要的數據和格式不同,這屬于應用層需求,而領域實體只有一個,在領域實體上通過標記DataMember進行序列化費力不討好,無法滿足復雜的應用需求。

        哪怕你只有一個Mvc網站,如果頁面上需要顯示一些領域實體不存在的數據,你根據這個需求,直接在領域實體上增加屬性是非常糟糕的做法,會嚴重污染你的領域模型,將大大降低領域實體的復用能力。

        從以上可以看出,對于一個比較復雜的系統,單憑領域實體很難完成任務,將太多的職責強加到領域實體上,會導致領域實體嚴重變形。

      數據傳輸對象介紹

        數據傳輸對象,即Data Transfer Object,簡稱DTO。

        一個為了減少方法調用次數而在進程間傳輸數據的對象,《企業應用架構模式》如是說。

        可以看出,DTO用于分布式環境,主要用來解決分布式調用的性能問題。同一進程內的對象調用,速度是非常快的,但跨進程調用,甚至跨網絡調用,性能下降N個數量級。為了提升性能,需要減少調用次數,這就要求把多次調用的結果打包成一個對象,在一次調用中返回盡量多的數據。

        上面是DTO的原始含義,下面來看看我的山寨用法。

        雖然我也取名為DTO,但我的動機并不完全是一次打包更多數據來提升性能,而是解決上面提到的幾個問題,當然它們之間有一定關系,可以看作一種變種用法。

      DTO的長相

        DTO是一個貧血對象,也就是它里面基本沒有方法,只有一堆屬性,并且所有屬性都具有public的getter和setter訪問器。

        DTO擁有public的setter訪問器,方便的解決了表現層的模型綁定問題。

        由于DTO不執行業務操作,僅用于傳遞數據,所以不應該定義非常復雜的對象引用關系,這樣就避免了循環引用,解決了對象序列化的問題。

      DTO的粒度

        DTO可以根據應用需求定義成不同的粒度,在一般情況下,DTO是聚合粒度,也就是說,一個領域層的聚合對應一個DTO,這樣做的一個好處是方便對CRUD操作進行抽象以及代碼生成。

        界面如果想保持簡單,應該盡量一個界面操作一個聚合,將聚合的數據映射到DTO后,傳給視圖展示。

        對于更加復雜的界面,需要在一個界面操作多個聚合,這種情況下,把需要的全部數據打包到DTO進行操作。

        從以上介紹中,你應該了解DTO不能理解為單表操作,它可以包含你需要的全部數據。

      DTO的位置

        DTO處于應用層,在表現層與領域層之間傳遞數據。

        DTO由應用層服務使用,應用層服務從倉儲中獲得聚合,并調用DTO轉換器將聚合映射為DTO,再將DTO傳遞給表現層。

        關于應用層服務,后續再專門介紹。

      DTO的映射

        聚合與DTO的轉換,看上去是一個簡單問題,在聚合與DTO幾乎完全一致的情況下,采用映射組件將非常省力。很多人采用AutoMapper,但它的性能稍微差了點,EmitMapper是更好的選擇,性能接近硬編碼。

        當DTO與聚合顯著不同時,我發現手工編碼更加清晰高效。我采用代碼生成器創建出一個代碼基礎,在有個性化需求時,手工修改映射代碼。

        我總是采用一個靜態類來擴展DTO和聚合,為它們添加相關的轉換方法。

      using Biz.Security.Domains.Models;
      using Util;
      
      namespace Biz.Security.Services.Dtos {
          /// <summary>
          /// 應用程序數據傳輸對象擴展
          /// </summary>
          public static class ApplicationDtoExtension {
              /// <summary>
              /// 轉換為應用程序實體
              /// </summary>
              /// <param name="dto">應用程序數據傳輸對象</param>
              public static Application ToEntity( this ApplicationDto dto ) {
                  return new Application( dto.Id.ToGuid() ) {
                      Code = dto.Code,
                      Name = dto.Name,
                      Note = dto.Note,
                      Enabled = dto.Enabled,
                      CreateTime = dto.CreateTime,
                      Version = dto.Version,
                  };
              }
      
              /// <summary>
              /// 轉換為應用程序數據傳輸對象
              /// </summary>
              /// <param name="entity">應用程序實體</param>
              public static ApplicationDto ToDto( this Application entity ) {
                  return new ApplicationDto {
                      Id = entity.Id.ToString(),
                      Code = entity.Code,
                      Name = entity.Name,
                      Note = entity.Note,
                      Enabled = entity.Enabled,
                      CreateTime = entity.CreateTime,
                      Version = entity.Version,
                  };
              }
          }
      }

       

      DTO 與 ViewModel比較

        ViewModel是為特定視圖專門定義的實體對象,專為該視圖服務。

        對于WPF,ViewModel是必須的,用來支持MVVM模式進行雙向綁定。

        那么MVC呢,一定需要它嗎?

        由于采用了DTO,在一般情況下,我都把這個DTO當作ViewModel來使用。如果界面上需要某個屬性,我會直接添加到DTO上。

        一個例外是,如果MVC的界面非常復雜,我感覺把大量的垃圾屬性加到DTO上不合適,就會創建專門的ViewModel。

      查詢實體介紹

        查詢實體這個說法,是我亂取的,估計你在其它地方也沒有聽說過。使用它的原因,是用來配合我的查詢組件一起工作。

        我前面已經介紹過查詢相關的內容,核心思想是通過判斷一個可空屬性,自動完成空值判斷,這是一個強大的特性,幫助你免于編寫大量雜亂無章的判斷

        查詢實體的基本特征就是所有屬性必須可空,并且它足夠簡單,不會擁有集合那樣的子對象,所有屬性都是扁平化的。

        通過傳遞查詢實體,表現層可以做到盡量簡單,由于表現層支持模型綁定,甚至不需要代碼,省力是我搭建框架的一個基本出發點。

        當然查詢實體只支持簡單查詢,不支持靈活的動態查詢,比如讓客戶設置查詢運算符等,暫時沒有這方面的需求,如果后續有需求,會擴展一個出來。

        查詢實體示例:

      using System.ComponentModel.DataAnnotations;
      using Util;
      using Util.Domains.Repositories;
      
      namespace Biz.Security.Domains.Queries {
          /// <summary>
          /// 應用程序查詢實體
          /// </summary>
          public class ApplicationQuery : Pager {
              /// <summary>
              /// 應用程序編號
              /// </summary>
              [Display( Name = "應用程序編號" )]
              public System.Guid? ApplicationId { get; set; }
      
              private string _code = string.Empty;
              /// <summary>
              /// 應用程序編碼
              /// </summary>
              [Display( Name = "應用程序編碼" )]
              public string Code {
                  get { return _code == null ? string.Empty : _code.Trim(); }
                  set { _code = value; }
              }
      
              private string _name = string.Empty;
              /// <summary>
              /// 應用程序名稱
              /// </summary>
              [Display( Name = "應用程序名稱" )]
              public string Name {
                  get { return _name == null ? string.Empty : _name.Trim(); }
                  set { _name = value; }
              }
      
              private string _note = string.Empty;
              /// <summary>
              /// 備注
              /// </summary>
              [Display( Name = "備注" )]
              public string Note {
                  get { return _note == null ? string.Empty : _note.Trim(); }
                  set { _note = value; }
              }
      
              /// <summary>
              /// 啟用
              /// </summary>
              [Display( Name = "啟用" )]
              public bool? Enabled { get; set; }
      
              /// <summary>
              /// 起始創建時間
              /// </summary>
              [Display( Name = "起始創建時間" )]
              public System.DateTime? BeginCreateTime { get; set; }
      
              /// <summary>
              /// 結束創建時間
              /// </summary>
              [Display( Name = "結束創建時間" )]
              public System.DateTime? EndCreateTime { get; set; }
      
              /// <summary>
              /// 添加描述
              /// </summary>
              protected override void AddDescriptions() {
                  base.AddDescriptions();
                  AddDescription( "應用程序編號", ApplicationId );
                  AddDescription( "應用程序編碼", Code );
                  AddDescription( "應用程序名稱", Name );
                  AddDescription( "備注", Note );
                  AddDescription( "啟用", Enabled.Description() );
                  AddDescription( "起始創建時間", BeginCreateTime );
                  AddDescription( "結束創建時間", EndCreateTime );
              }
          }
      }

       

      總結

      最后來總結一下:

        1. 領域實體是系統的中心,是業務邏輯的主要放置場所,應該盡量關閉業務邏輯操作的屬性,以避免有人能繞過你的方法直接操作數據。

        2. DTO是數據傳輸對象,原義是用來在分布式系統中一次傳輸更多數據,以減少調用次數,提升性能。

        3. 我的DTO用法離原義相去甚遠,只是借用了DTO的名詞,屬于變種。DTO為我解決了如下幾個問題:

      • 領域實體在表現層進行模型綁定時可能失敗
      • 序列化領域實體可能失敗
      • 領域實體無法應對多客戶端應用需求,通過創建多套DTO甚至應用層,可以為不同的應用提供服務,而領域層不變,它是系統的中心。

        4. DTO是包含大量屬性,沒有方法的貧血實體,所有屬性都開放getter和setter,以方便模型綁定和序列化。

        5. DTO一般情況下是聚合去除方法后的模樣,主要好處是方便抽象CRUD及代碼生成。

        6. DTO位于應用層,由應用層服務操作它。

        7. DTO的映射可以采用映射組件,也可以代碼生成方便隨時修改,以你覺得方便為主。

        8. 僅在WPF環境下才需要為每個視圖創建一個對應的ViewModel,MVC一般使用DTO即可,僅為復雜界面創建ViewModel。

        9. 查詢實體是為了配合查詢組件引入的構造,目的是幫助查詢組件完成空值判斷,并且簡化表現層的調用。

       

       

        本文分享了我在幾個構造類型上的認識和經驗,希望大家積極討論,更希望高手能指正我的不足,幫助我與大家一起進步。

       

        .Net應用程序框架交流QQ群: 386092459,歡迎有興趣的朋友加入討論。

        .Net Easyui開發交流QQ群(本群僅限Easyui開發者,非Easyui開發者勿進):157809322

        謝謝大家的持續關注,我的博客地址:http://www.rzrgm.cn/xiadao521/

       

      posted @ 2015-03-31 01:05  何鎮汐  閱讀(12696)  評論(64)    收藏  舉報
      主站蜘蛛池模板: 久久发布国产伦子伦精品| 久久天天躁狠狠躁夜夜躁| 精品久久久久中文字幕日本| 午夜国产福利片在线观看| 思思久99久女女精品| 大肉大捧一进一出好爽视频mba| 无码专区 人妻系列 在线| 亚洲色偷偷偷网站色偷一区| 日韩精品国产精品十八禁| 人妻伦理在线一二三区| 亚洲欧美人成网站在线观看看| 国产精品极品美女自在线观看免费| 久久中文字幕一区二区| 亚洲国产精品人人做人人爱| 中文字幕在线国产精品| 99国产欧美久久久精品蜜芽| 国产成人精品一区二区秒拍1o| 粉嫩一区二区三区国产精品| 日韩不卡无码精品一区高清视频| 国模雨珍浓密毛大尺度150p| 凤城市| 日韩有码中文字幕国产| 久久se精品一区精品二区国产| 国产日韩一区二区天美麻豆| 亚洲精品欧美综合二区| 精品国产成人午夜福利| 国产成人高清亚洲综合| 久热99热这里只有精品| 一级做a爰片在线播放| 国产精品黄色片| 亚洲成亚洲成网中文字幕| 加勒比在线中文字幕一区二区| 被灌满精子的少妇视频| 精品人妻少妇一区二区三区在线 | 久久国产免费观看精品3| 久久国产精品夜色| 成人午夜精品无码区久久| 欧美牲交videossexeso欧美| 97精品亚成在人线免视频| 91福利国产午夜亚洲精品| 国产成人精品国产成人亚洲|