日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于ABP落地领域驱动设计-05.实体创建和更新最佳实践

發(fā)布時間:2023/12/4 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于ABP落地领域驱动设计-05.实体创建和更新最佳实践 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

圍繞DDDABP Framework兩個核心技術(shù),后面還會陸續(xù)發(fā)布核心構(gòu)件實現(xiàn)綜合案例實現(xiàn)系列文章,敬請關(guān)注!?ABP Framework 研習(xí)社(QQ群:726299208)?ABP Framework 學(xué)習(xí)及實施DDD經(jīng)驗分享;示例源碼、電子書共享,歡迎加入!

數(shù)據(jù)傳輸對象

DTO 是簡單對象,用于在應(yīng)用層和展示層傳遞狀態(tài)數(shù)據(jù)。所以,應(yīng)用服務(wù)方法返回 DTO。

DTO原則和最佳實踐:

?DTO應(yīng)該可序列化,因為大多數(shù)時候,需要網(wǎng)絡(luò)傳輸。?應(yīng)該有一個無參構(gòu)造函數(shù)?不能包含任何業(yè)務(wù)邏輯?不能繼承或引用實體

輸入DTO輸出DTO在本質(zhì)上不同:一個用于給應(yīng)用服務(wù)方法傳遞參數(shù),一個作為應(yīng)用服務(wù)方法的返回值,根據(jù)業(yè)務(wù)需要區(qū)別對待。

輸入DTO最佳實踐

不要在輸入DTO中定義不使用的屬性

只定義需要用的屬性,否則,無用的屬性只會讓客戶端在使用應(yīng)用服務(wù)方法時感到困惑。當然可以定義可選屬性,但是確保當客戶端在使用時,不應(yīng)該影響到用例的工作方式。

這條規(guī)則看起來沒什么必要,誰會為方法倉儲(輸入DTO)添加不使用的屬性呢?但是,它經(jīng)常發(fā)生,尤其是當你想重用輸入DTO對象時,會將多個DTO屬性放在一個DTO對象中。

不要重用輸入DTO

為每個用例(應(yīng)用服務(wù)方法)定義特定的輸入DTO,否則,在某些情況下不會添加一些不被使用的屬性,這就違反了上面定義的規(guī)則。

有時候,在兩個不同的用例中使用相同的DTO似乎很有吸引力,因為他們?nèi)绱讼嗨啤I踔?#xff0c;當前是一模一樣,可能后面隨著業(yè)務(wù)變化才會有可能不同,此時也應(yīng)該不要重用輸入DTO。因為和用例間的耦合相比,代碼復(fù)制可能是更好的做法。

重用DTO的另一種方式是:DTO繼承,這同樣會產(chǎn)生上面描述的問題.。

示例:用戶應(yīng)用服務(wù)

public interface IUserAppService:IApplicationService {Task CreateAsync(UserDto input);Task UpdateAsync(UserDto input);Task ChangePasswordAsync(UserDto input); }

IUserAppService?在所有方法(用例)使用?UserDto?作為輸入DTO,UserDto定義如下:

public class UserDto {public Guid Id{get;set;}public string UserName{get;set;}public string Email{get;set;}public string Password{get;set;}public DateTime CreationTime{get;set;} }

?Id?在 Create 方法中不被使用,因為 Id 由服務(wù)器生成。?Password?在 Update 方法中不使用,因為有修改密碼的單獨方法。?CreationTime?未被使用,且不應(yīng)該由客戶端發(fā)送給服務(wù)端,應(yīng)該在服務(wù)端設(shè)置創(chuàng)建時間。

正確的實現(xiàn),如下:

public interface IUserAppService:IApplicationService {Task CreateAsync(UserCreationDto input);Task UpdateAsync(UserUpdateDto input);Task ChangePasswordAsync(UserChangePasswordDto input); }

然后定義對應(yīng)的DTO類:

public class UserCreationDto {public string UserName {get;set;}public string Email{get;set;}public string Password{get;set;} }public class UserUpdateDto {public Guid Id{get;set;}public string UserName{get;set;}public string Email{get;set;} }public class UserChangePasswordDto {public Guid Id{get;set;}public string Password{get;set;} }

盡管需要編寫更多的代碼,但是這是一種更易維護的方法。

特殊情況:舉個例子,如果你有一個報表頁,頁面中有多個過濾條件,對應(yīng)多個應(yīng)用服務(wù)方法(顯示報表、導(dǎo)出Excel、導(dǎo)出CSV),此時應(yīng)該使用相同的輸入DTO參數(shù),返回不同的結(jié)果。因為當頁面過濾條件改變時,修改一個DTO而對整個頁面對應(yīng)的應(yīng)用服務(wù)方法參數(shù)生效。

輸入DTO中驗證邏輯

?僅在DTO內(nèi)部執(zhí)行簡單驗證,使用數(shù)據(jù)注解特性或?qū)崿F(xiàn)?IValidatableObject?接口?不要執(zhí)行領(lǐng)域驗證,舉個例子,不要在DTO中檢測用戶名是否唯一的驗證。

示例:使用數(shù)據(jù)注解特性

using System.ComponentModel.DataAnnotations;namespace IssueTracking.Users {public class UserCreationDto{[Required][StringLength(UserConsts.MaxUserNameLength)]public string UserName {get;set;}[Required][EmailAddress][StringLength(UserConsts.MaxEmailLength)]public string Email{get;set;}[Required][StringLength(UserConsts.MaxEmailLength,MinimumLength=UserConsts.MinPasswordLength)]public string Password{get;set;}} }

ABP框架自動驗證輸入DTO,驗證失敗則拋出AbpValidationException異常,返回 400 HTTP 狀態(tài)碼。

某些開發(fā)者認為將驗證規(guī)則和DTO類分離可能會更好。我們認為聲明式(數(shù)據(jù)注解)是實用的,不會導(dǎo)致任何設(shè)計問題。當然,ABP支持 FluentValidation集成。

輸出DTO最佳實踐

?保持輸出DTO數(shù)量最小,盡可能重用,但是不能將輸入DTO作為輸出DTO使用。?輸出DTO可以包含比用例需要的更多屬性?Create?和?Update?方法中返回DTO

以上建議的主要原因是:

?使客戶端代碼易于開發(fā)和擴展

?在客戶端端處理不同但相似的DTO容易混淆?輸入DTO中的更多屬性可能未來會在UI/客戶端中被使用,返回實體的所有屬性(已經(jīng)考慮過安全性和特殊情況)使客戶端代碼易于改進,而不需要修改后端代碼。?如果是通過API暴露給第三方客戶端,避免不同需求返回不同DTO

?使服務(wù)端代碼易于開發(fā)和擴展

?更少的類,易于理解和維護?可以重用實體到DTO(AutoMapper)的對象映射代碼?不同方法返回相同類型,使添加新方法變得簡單明了。

示例:從不同方法返回不同DTO

public interface IUserAppService:IApplicationService {UserDto Get(Guid id);List<UserNameAndEmailDto> GetUserNameAndEmail(Guid id);List<string> GetRoles(Guid id);List<UserListDto> GetList();UserCreateResultDto Create(UserCreationDto input);UserUpdateResultDto Update(UserUpdateDto input); }

示例中沒有使用異步方法,在實際開發(fā)時應(yīng)該是異步方法。

上面的示例代碼中,為每個方法返回不同DTO類型,這樣會導(dǎo)致我們需要處理非常多的數(shù)據(jù)查詢,映射實體到DTO的重復(fù)代碼。

按照以下方式定義就簡單多了:

public interface IUserAppService:IApplicationService {UserDto Get(Guid id);List<UserDto> GetList();UserDto Create(UserCreationDto input);UserDto Update(UserUpdateDto input); }

使用一個輸出DTO:

public class UserDto {public Guid Id{get;set;}public string UserName{get;set;}public string Email{get;set;}public DateTiem CreationTime{get;set;}public List<string> Roles{get;set;} }

?移除?GetUserNameAndEmail?和?GetRoles?方法,因為 Get 方法已經(jīng)返回足夠需要的信息。?GetList?返回對象與?Get?相同?Create?和?Update?同樣返回?UserDto

由此可見,返回相同DTO更加簡潔。

為什么創(chuàng)建或更新之后要返回DTO??想象一個用例場景,在頁面中顯示表格數(shù)據(jù),當更新之后,獲取返回對象,并對表格數(shù)據(jù)源進行更新,這樣就不需要再次調(diào)用?GetList?方法,這是我們建議在?Create?和?Update?方法中返回 DTO 的原因。

討論

以上關(guān)于輸出DTO的建議,并不適用所有場景。

出于性能考慮,這些建議可以被忽略,特別是當存在大型數(shù)據(jù)集返回結(jié)果時,或者用戶界面需要發(fā)起很多并發(fā)請求時,此時應(yīng)該創(chuàng)建特定的輸出DTO,只包含盡可能少的信息。

可維護性和性能,需要開發(fā)者權(quán)衡,上面的建議適用于性能損失可忽略不計的應(yīng)用。

對象映射

自動對象映射是一個非常有用的工具,兩個對象的屬性相同或相似,將一個對象的值復(fù)制給另一個對象。

DTO和實體類通常具有相同或相似的屬性,通常需要根據(jù)實體和業(yè)務(wù)需求來創(chuàng)建DTO對象。ABP框架對象映射基于 AutoMapper,相比手動賦值,效率更高。

?僅對實體到輸出DTO使用自動對象映射。?輸入DTO到實體不適用自動對象映射。

不使用輸入DTO到實體自動映射的原因:

1.實體類通常有構(gòu)造函數(shù),接收參數(shù)并在創(chuàng)建時,進行參數(shù)驗證。自動對象映射操作通常需要無參構(gòu)造函數(shù)創(chuàng)建對象。2.實體屬性設(shè)置器大多是私有的,應(yīng)該使用方法設(shè)置屬性值。3.通常需要仔細驗證和處理用戶/客戶端輸入,而不是盲目地映射到實體屬性。

雖然其中一些問題可以通過映射配置來解決(例如,AutoMapper允許定義自定義映射規(guī)則),但它使你的業(yè)務(wù)邏輯隱含/隱藏,并與基礎(chǔ)設(shè)施緊密耦合。我們認為業(yè)務(wù)代碼應(yīng)該是明確的、清晰的、容易理解的。

學(xué)習(xí)幫助

圍繞DDDABP Framework兩個核心技術(shù),后面還會陸續(xù)發(fā)布核心構(gòu)件實現(xiàn)綜合案例實現(xiàn)系列文章,敬請關(guān)注!

ABP Framework 研習(xí)社(QQ群:726299208)?專注 ABP Framework 學(xué)習(xí)及DDD實施經(jīng)驗分享;示例源碼、電子書共享,歡迎加入!

總結(jié)

以上是生活随笔為你收集整理的基于ABP落地领域驱动设计-05.实体创建和更新最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。