首頁/ 汽車/ 正文

基於ABP實現DDD--實體建立和更新

本文主要介紹了透過建構函式和領域服務建立實體2種方式,後者多用於在建立實體時需要其它業務規則檢測的場景。最後介紹了在應用服務層中如何進行實體的更新操作。

一。透過建構函式建立實體

假如Issue的聚合根類為:

public class Issue : AggregateRoot{ public Guid RepositoryId { get; private set; } //不能修改RepositoryId,原因是不支援把一個Issue移動到另外一個Repository下面 public string Title { get; private set; } //不能直接修改Title,可以透過SetTitle()修改,主要是在該方法中要加入對Title不能重複的校驗 public string Text { get; set; } //可以直接修改 public Guid? AssignedUserId { get; internal set; } //同一個程式集中是可以修改AssignedUserId的 // 公有建構函式 public Issue(Guid id, Guid repositoryId, string title, string text=null) : base(id) { RepositoryId = repositoryId; Title = Check。NotNullOrWhiteSpace(title, nameof(title)); Text = text; //可為空或者null } // 私有建構函式 private Issue() {} // 修改Title的方法 public void SetTitle(string title) { // Title不能重複 Title = Check。NotNullOrWhiteSpace(title, nameof(title)); } // 。。。}

在應用服務層建立一個Issue的過程如下:

public class IssueAppService : ApplicationService。IIssueAppService{ private readonly IssueManager _issueManager; //Issue領域服務 private readonly IRepository _issueRepository; //Issue倉儲 private readonly IRepository _userRepository; //User倉儲 // 公有建構函式 public IssueAppService(IssueManager issueManager, IRepository issueRepository, IRepository userRepository) { _issueManager = issueManager; _issueRepository = issueRepository; _userRepository = userRepository; } // 透過建構函式建立Issue public async Task CreateAssync(IssueCreationDto input) { var issue = new Issue(GuidGenerator。Create(), input。RepositoryId, input。Title, input。Text); } if(input。AssigneeId。HasValue) { // 獲取分配給Issue的User var user = await _userRepository。GetAsync(input。AssigneeId。Value); // 透過Issue的領域服務,將Issue分配給User await _issueManager。AssignAsync(issue, user); } // 插入和更新Issue await _issueRepository。InsertAsync(issue); // 返回IssueDto return ObjectMapper。Map(issue);}

二。透過領域服務建立實體

什麼樣的情況下會用領域服務建立實體,而不是透過實體建構函式來建立實體呢?主要用在建立實體時需要其它業務規則檢測的場景。比如,在建立Issue的時候,不能建立Title相同的Issue。透過Issue實體建構函式來建立Issue實體,這個是控制不住的。所以才會有透過領域服務建立實體的情況。 阻止從Issue的建構函式來建立Issue實體,需要將其建構函式的訪問許可權由public修改為internal:

public class Issue : AggregateRoot{ // 。。。 internal Issue(Guid id, Guid repositoryId, string title, string text = null) : base(id) { RepositoryId = repositoryId; Title = Check。NotNullOrEmpty(title, nameof(title)); Text = text; //允許為空或者null } // 。。。}

透過領域服務IssueManager中的CreateAsync()方法來判斷建立的Issue的Title是否重複:

public class IssueManager:DomainService{ private readonly IRepository _issueRepository; // Issue的倉儲 // 公有建構函式,注入倉儲 public IssueManager(IRepository issueRepository) { _issueRepository=issueRepository; } public async Task CreateAsync(Guid repositoryId, string title, string text=null) { // 判斷Issue的Title是否重複 if(await _issueRepository。AnyAsync(i=>i。Title==title)) { throw new BusinessException(“IssueTracking:IssueWithSameTitleExists”); } // 返回建立的Issue實體 return new Issue(GuidGenerator。Create(), repositoryId, title, text); }}

在應用服務層IssueAppService中透過IssueManager。CreateAsync()建立實體如下:

public class IssueAppService :ApplicationService。IIssueAppService{ private readonly IssueManager _issueManager; //Issue的領域服務 private readonly IRepository _issueRepository; //Issue的倉儲 private readonly IRepository _userRepository; //User的倉儲 // 公共的建構函式,注入所需的依賴 public IssueAppService(IssueManager issueManager, IRepository issueRepository, IRepository userRepository){ _issueManager=issueManager; _issueRepository=issueRepository; _userRepository=userRepository; } // 建立一個Issue public async Task CreateAsync(IssueCreationDto input) { // 透過領域服務的_issueManager。CreateAsync()建立實體,主要是保證Title不重複 var issue=await _issueManager。CreateAsync(input。RepositoryId, input。Title, input。Text); // 獲取User,並將Issue分配給User if(input。AssignedUserId。HasValue) { var user =await _userRepository。GetAsync(input。AssignedUserId。Value); await _issueManager。AssignToAsynce(issue,user); } // 插入和更新資料庫 await _issueRepository。InsertAsync(issue); // 返回IssueDto return ObjectMapper。Map(issue); }}// 定義Issue的建立DTO為IssueCreationDtopublic class IssueCreationDto{ public Guid RepositoryId{get;set;} [Required] public string Title {get;set;} public Guid? AssignedUserId{get;set;} public string Text {get;set;}}

現在有個疑問是為什麼不把Title的重複檢測放在領域服務層中來做呢,這就涉及一個區分核心領域邏輯還是應用邏輯的問題了。顯然這裡Title不能重複屬於核心領域邏輯,所以放在了領域服務中來處理。

為什麼標題重複檢測不在應⽤服務中實現?詳細的解釋參考

[1]。

三。實體的更新操作

接下來介紹在應用層IssueAppService中來update實體。定義UpdateIssueDto如下:

public class UpdateIssueDto{ [Required] public string Title {get;set;} public string Text{get;set;} public Guid? AssignedUserId{get;set;}}

實體更新操作的UpdateAsync()方法如下所示:

public class IssueAppService :ApplicationService。IIssueAppService{ private readonly IssueManager _issueManager; //Issue領域服務 private readonly IRepository _issueRepository; //Issue倉儲 private readonly IRepository _userRepository; //User倉儲 // 公有建構函式,注入依賴 public IssueAppService(IssueManager issueManager, IRepository issueRepository, IRepository userRepository){ _issueManager=issueManager; _issueRepository=issueRepository; _userRepository=userRepository; } // 更新Issue public async Task UpdateAsync(Guid id, UpdateIssueDto input) { // 從Issue倉儲中獲取Issue實體 var issue = await _issueRepository。GetAsync(id); // 透過領域服務的issueManager。ChangeTitleAsync()方法更新Issue的標題 await _issueManager。ChangeTitleAsync(issue,input。Title); // 獲取User,並將Issue分配給User if(input。AssignedUserId。HasValue) { var user = await _userRepository。GetAsync(input。AssignedUserId。Value); await _issueManager。AssignToAsync(issue, user); } issue。Text=input。Text; // 更新和儲存Issue // 儲存實體更改是應用服務方法的職責 await _issueRepository。UpdateAsync(issue); // 返回IssueDto return ObjectMapper。Map(issue); }}

需要在IssueManager中新增ChangeTitle():

public async Task ChangeTitleAsync(Issue issue,string title){ // Title不變就返回 if(issue。Title==title) { return; } // Title重複就丟擲異常 if(await _issueRepository。AnyAsync(i=>i。Title==title)) { throw new BusinessException(“IssueTracking:IssueWithSameTitleExists”); } // 請它情況更新Title issue。SetTitle(title);}

修改Issue類中SetTitle()方法的訪問許可權為internal:

internal void SetTitle(string title){ Title=Check。NotNullOrWhiteSpace(title,nameof(title));}

參考文獻:

[1]基於ABP Framework實現領域驅動設計:https://url39。ctfile。com/f/2501739-616007877-f3e258?p=2096 (訪問密碼: 2096)

相關文章

頂部