四虎精品视频-四虎精品成人免费网站-四虎黄色网-四虎国产视频-国产免费91-国产蜜臀97一区二区三区

面向領(lǐng)域驅(qū)動架構(gòu)的查詢實現(xiàn)方式

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

  聚合與聚合根

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

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

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

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

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

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知識庫面向領(lǐng)域驅(qū)動架構(gòu)的查詢實現(xiàn)方式,轉(zhuǎn)載需保留來源!

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

主站蜘蛛池模板: 黄视频在线播放| 霹雳火 电影| 孽子 电影| 影片 - theav| 初恋50次 电影| 中女| 范瑞君| 《欲望中的女人》| 中国宇航员遇难| 冰封侠| 狼来了电影免费观看| 一个月经代表七个版本| 欧美一级在线视频| xzj| 食人鱼电影| 转身离开| 欲望之屋2电视剧免费观看完整版高清| 黑龙江省地图高清全图| 妈妈的朋字韩剧| a面b面| 手心里的温柔女声版| 电影疯狂| 《与凤行》演员表| bobby charlton| 婴儿睡眠时间对照表| 玛丽亚小泽| 人口高质量发展形势与政策论文| 老男人gay同性gay做受| 黄老汉| 野性的呼唤巴克原版| 苹果恋爱多| kanako| 北京卫视手机直播| angie faith| 男骑女| 红电视剧演员表| 美女洗澡网站| 火船 电影| 爱爱内含光在线播放| 火与剑| 侠侣探案|