一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

面向領域驅動架構的查詢實現方式

  在上一篇文章《.NET應用框架架構設計實踐 - 概述》的評論部分,有網友提出了一個在面向領域驅動架構的實踐中比較常見的問題:“DDD使用聚合根訪問,那例如那些通用查詢如何實現?難道都要經過聚合根多步得到么?DDD如何實現關聯表的查詢,例如3表關聯查詢?”這個問題比較泛,涉及的內容也比較多,我就單獨一篇文章介紹一下我對這個問題的看法。關于上面問題中的“通用查詢”- 呃,這個定義比較模糊,我只能給出我的一些想法或者經驗性的東西,我在本文中的經驗與觀點并不一定會100%適合您的應用場景,但我想應該還是具有一定指導性意義的。

  聚合與聚合根

  我想,還是從聚合根談起吧。聚合根是DDD中的概念,不管是經典的DDD架構,還是基于事件驅動的CQRS架構,其實它們之間絕大部分概念都是相通的,比如實體、值對象、服務、工廠、倉儲以及聚合/聚合根等。根據我的理解,聚合根是一個實體,它保持著與其它實體/值對象的引用,并與這些實體/值對象一起,來表達領域的通用語言中的一個唯一的無二義的邏輯概念。比如最常見的“客戶(Customer)”,在“在線銷售”的領域中,“客戶”不僅包含它所指代的那個個人(或者是組織)的名稱、聯系電話、聯系電郵,還會包含它的聯系地址(Contact Address)以及送貨地址(Delivery Address),那么就Address而言,在此我們可以將其視為值對象,因為我們只關心地址本身所包含的信息。在這里,“客戶(Customer)”不僅是實體,而且是“客戶-地址”所組成的對象集合(聚合)的聚合根。

  在這里會有異議的地方就是“銷售訂單(Sales Order)”是否應該屬于“客戶(Customer)”聚合。我覺得這還是要看在當前的領域中,“銷售訂單”是不是“客戶”的必有信息,換句話說,“客戶”是不是沒有“銷售訂單”就不成其為“客戶”。我想,在大多數情況下,“客戶”應該是一個可以脫離“銷售訂單”而單獨存在的實體,那這樣的話,“銷售訂單”也將不屬于“客戶”聚合。

  現在讓我們來看“在線銷售”領域中的另一部分:銷售訂單。當然,“銷售訂單(Sales Order)”是實體,本身也是訂單主體與“訂單明細(Sales Lines)”所組成的聚合的聚合根,這是很自然的事情,因為“銷售訂單”如果沒有訂單的明細信息,也就失去了訂單本身的意義。此外,“客戶”實體也是這個聚合的一個組成部分,這也很好理解,“銷售訂單”本身就是客戶下達的,它不可能脫離“客戶”而憑空存在。于是,以“銷售訂單”為根的聚合,還包括“客戶”實體,以及“訂單明細”(至于“訂單明細”是實體還是值對象,這跟具體的領域定義有密切關系,比如如果涉及商品Item與購買量的打折等內容,那么“訂單明細”就需要以實體方式處理,否則可以設計成“值對象”以減小系統開銷,本文繞過這個問題的討論)。在作進一步討論之前,讓我們回顧一下DDD中的倉儲。DDD告訴我們,倉儲是作用在聚合根上的:領域模型中對象的保存與讀取都是以聚合為單位而進行的。

  通過上面的討論,針對“在線銷售”領域,我們大致得到了如下的領域模型(為了縮短篇幅,圖中可能會省略某些部分)

image  問題來了,如果我們需要獲得某個“客戶”的所有訂單,該怎么辦?在上面的領域模型中,Customer實體并沒有某個屬性或者方法來獲得其所有的銷售訂單。那么在遇到這樣的問題時,通常都是通過SalesOrder的倉儲,配合規約(Specification)來篩選出所有符合特定“客戶”條件的銷售訂單,然后由倉儲返回銷售訂單的列表。你或許會覺得這種做法比較不科學,你會覺得應該通過Customer實體的某個屬性(比如SalesOrders)來獲得該“客戶”所擁有的所有銷售訂單,這樣會更直截了當些。但在上面我們已經對這個領域模型進行了討論,在我們的案例中,Customer是一個獨立的實體,SalesOrder不是它的必要組成部分。于是,為了維護領域模型的完整性,我們需要利用“銷售訂單”的倉儲來完成這個功能。偽代碼如下:

public interface ISpecification<T>
{
bool IsSatisfiedBy(T obj);
}

public abstract class Specification<T> : ISpecification<T>
{
public abstract Expression<Func<T, bool>> Expression { get; }

public bool IsSatisfiedBy(T obj)
{
return this.Expression.Compile()(obj);
}
}

public class OrderCustomerMatchesSpecification : Specification<SalesOrder>
{
private Customer customer;
public OrderCustomerMatchesSpecification(Customer customer)
{
this.customer = customer;
}
public override Expression<Func<SalesOrder, bool>> Expression
{
get { return p => p.Customer.Id.Equals(customer.Id); }
}
}

public interface IRepository<T>
where T : IAggregateRoot
{
void Add(T aggregateRoot);
List
<T> GetAllBySpecification(ISpecification<T> spec);
}

public class MemoryRepository<T> : IRepository<T>
where T : IAggregateRoot
{
private readonly List<T> store =new List<T>();

public void Add(T aggregateRoot)
{
if (!this.store.Exists(p => p.Id.Equals(aggregateRoot.Id)))
this.store.Add(aggregateRoot);
}

public List<T> GetAllBySpecification(ISpecification<T> spec)
{
return this.store.Where(spec.IsSatisfiedBy).ToList();
}
}

ISpecification
<SalesOrder> spec =new OrderCustomerMatchesSpecification(custDaxNET);
List
<SalesOrder> daxNETOrders = salesOrderRepository.GetAllBySpecification(spec);

it知識庫面向領域驅動架構的查詢實現方式,轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: 午夜黄大色黄大片美女图片 | 国产普通话一二三道 | 一区二区三区四区免费视频 | 激情综合网五月激情 | 激情小说区 | 亚洲午夜国产精品无卡 | 四虎欧美永久在线精品免费 | 国产一区二区三区免费 | 国产乱来视频 | 亚洲日韩中文字幕 | 免费一级毛片不卡不收费 | 久久国产精品-久久精品 | 狠狠操操操 | 国产剧情在线视频 | 九九色视频| 99在线精品免费视频九九视 | 91免费视频观看 | 蜜桃久久久 | 国产亚洲精品2021自在线 | 国产精品亚洲欧美日韩久久 | 国产三区视频 | 看全色黄大色大片 | 午夜网站视频 | 激情六月在线视频观看 | 欧美另类videosbestsex视频 | 97人人看 | 精品一区二区视频 | 一区二区在线精品免费视频 | 美女很黄很黄是免费的·无遮挡网站 | 中文字幕在线观看一区 | 91福利在线视频 | 国产高清精品久久久久久久 | 国产成人精品免费视频大全办公室 | 四虎海外影库www4hu | 国产精品久久精品福利网站 | 精品视频一区二区三区在线观看 | 亚洲无吗在线视频 | 久久久夜间小视频 | 国产嫩草在线观看 | 巨大巨粗巨长的黑吊免费视频 | 婷婷丁香在线 |