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

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

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

      EntityFramework之領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)實(shí)踐【擴(kuò)展閱讀】:CQRS體系結(jié)構(gòu)模式

      CQRS體系結(jié)構(gòu)模式

      本文將對(duì)CQRS(Command Query Responsibility Segregation,命令查詢職責(zé)分離)模式做一個(gè)相對(duì)全面的介紹??梢赃@么說(shuō),CQRS打破了經(jīng)典的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)實(shí)踐,在應(yīng)用CQRS的整個(gè)過(guò)程中,你將會(huì)以另一種不同的角度去考慮問(wèn)題并尋求解決方案。比如,CQRS是事件驅(qū)動(dòng)的體系結(jié)構(gòu),事件是如何產(chǎn)生如何分發(fā)又是如何處理的?事件驅(qū)動(dòng)的體系結(jié)構(gòu)適用于哪些類(lèi)型的應(yīng)用系統(tǒng)?CQRS中的倉(cāng)儲(chǔ),與經(jīng)典DDD中的倉(cāng)儲(chǔ)又有何異同?等等這些問(wèn)題,都給我們留下了無(wú)限的思考空間。

      背景

      在講CQRS之前,我們先了解一下CQS(Command-Query Separation,命令查詢)模式。名字上看,兩者沒(méi)什么差別,然而CQRS應(yīng)該說(shuō)是,在DDD的實(shí)踐中引入CQS理論而出現(xiàn)的一種體系結(jié)構(gòu)模式。CQS模式最早由著名軟件大師Bertrand Meyer(Eiffel語(yǔ)言之父,面向?qū)ο箝_(kāi)-閉原則OCP提出者)提出,他認(rèn)為,對(duì)象的行為僅有兩種:命令和查詢,不存在第三種情況。用他自己的話來(lái)說(shuō),就是:“提問(wèn)永遠(yuǎn)無(wú)法改變答案”。根據(jù)CQS,任何方法都可以拆分為命令和查詢兩個(gè)部分。比如,下面的代碼:

      隱藏行號(hào) 復(fù)制代碼 代碼
      1. private int i = 0;
      2. 
        
      3. private int Add(int factor)
      4. {
      5.     i += factor;
      6.     return i;
      7. }
      8. 
        

      可以替換為:

      隱藏行號(hào) 復(fù)制代碼 代碼
      1. private void AddCommand(int factor)
      2. {
      3.     i += factor;
      4. }
      5. 
        
      6. private int QueryValue()
      7. {
      8.     return i;
      9. }
      10. 
        

      當(dāng)命令和查詢被分離的時(shí)候,我們將會(huì)有更多的機(jī)會(huì)去把握整個(gè)事情的細(xì)節(jié)。比如我們可以對(duì)系統(tǒng)的“命令”部分和“查詢”部分分別采用不同的技術(shù)架構(gòu),以使得系統(tǒng)具有更好的擴(kuò)展性,并獲得更好的性能。在DDD領(lǐng)域中,Greg Young和Eric Evans根據(jù)Bertrand Meyer的CQS模式,結(jié)合實(shí)際項(xiàng)目經(jīng)驗(yàn),總結(jié)了CQRS體系結(jié)構(gòu)模式。

      結(jié)構(gòu)

      整個(gè)系統(tǒng)結(jié)構(gòu)被分為兩個(gè)部分:命令部分和查詢部分。我根據(jù)自己的體會(huì),描繪了CQRS的體系結(jié)構(gòu)簡(jiǎn)圖如下,供大家參考。在討論CQRS體系結(jié)構(gòu)之前,我們有必要事先弄清楚這樣幾個(gè)概念:對(duì)象狀態(tài)、事件溯源(Event Sourcing)、快照(Snapshots)以及事件存儲(chǔ)(Event Store)。討論的過(guò)程中你會(huì)發(fā)現(xiàn),很多概念與我們之前對(duì)經(jīng)典DDD的理解相比,有著很大的不同。

      CQRS體系結(jié)構(gòu)模式

       

       

      對(duì)象狀態(tài)

       

      這是一個(gè)大家耳熟能詳?shù)母拍盍恕J裁词菍?duì)象狀態(tài)?在被面向?qū)ο缶幊蹋∣OP)“熏陶”了很久的朋友,一聽(tīng)到“對(duì)象狀態(tài)”,馬上想到了一對(duì)對(duì)的getter/setter屬性。尤其是.NET程序員,在C# 3.0及以后版本中,引入了Auto-Property的概念,于是,對(duì)象的屬性就很容易地成為了對(duì)象狀態(tài)的代名詞。在這里,我們應(yīng)該看到問(wèn)題的本質(zhì),即使是Auto-Property,它也無(wú)非是對(duì)對(duì)象字段的一種封裝,只不過(guò)在使用Auto-Property的時(shí)候,C#編譯器會(huì)在后臺(tái)創(chuàng)建一個(gè)私有的、匿名的字段(field),而Property則成為了從外部訪問(wèn)該字段的唯一途徑。換句話說(shuō),對(duì)象的狀態(tài)是保存在這些字段里的,對(duì)象屬性無(wú)非是訪問(wèn)字段的facade。在這里澄清這樣一個(gè)事實(shí),就是為了當(dāng)你繼續(xù)閱讀本文的時(shí)候,不至于對(duì)事件溯源(Event Sourcing)的某些具體實(shí)現(xiàn)感到困惑。在Event Sourcing的具體實(shí)現(xiàn)中,領(lǐng)域?qū)ο蟛辉傩枰邆涔械膶傩?,至少外界無(wú)法通過(guò)公有屬性改變對(duì)象狀態(tài)(即setter被定義為private,甚至沒(méi)有setter)。這與經(jīng)典的DDD設(shè)計(jì)相比,無(wú)疑是一個(gè)重大改變。例如,現(xiàn)在我要改變某個(gè)Customer的狀態(tài),如果采用經(jīng)典DDD的實(shí)現(xiàn)方式,就是:

      隱藏行號(hào) 復(fù)制代碼 代碼
      1. [TestMethod]
      2. public void TestChangeCustomerName()
      3. {
      4.     IocContainer c = IocContainer.GetIocContainer();
      5.     using (IRepositoryTransactionContext ctx = c.GetService<IRepositoryTransactionContext>())
      6.     {
      7.         IRepository<Customer> customerRepository = ctx.GetRepository<Customer>();
      8.         Customer customer = customerRepository
      9.             .Get(Specification<Customer>
      10.             .Eval(p=>p.FirstName.Equals("sunny") && p.LastName.Equals("chen")));
      11.         // Here we use the properties directly to update the state
      12.         customer.FirstName = "dax"; 
      13.         customer.LastName = "net";
      14.         customerRepository.Update(customer);
      15.         ctx.Commit();
      16.     }
      17. }
      18. 
        

      現(xiàn)在,很多ORM工具都需要聚合根具有public的getter/setter,這本身就是技術(shù)實(shí)現(xiàn)上的一種約束,比如某些ORM工具會(huì)使用reflection,通過(guò)讀寫(xiě)對(duì)象的property來(lái)改變對(duì)象狀態(tài)。為什么ORM工具要選擇properties,而不是fields?因?yàn)檫@些框架不希望自己的介入會(huì)改變對(duì)象對(duì)其狀態(tài)的封裝級(jí)別(也就是訪問(wèn)限制)。在引入CQRS后,ORM已經(jīng)沒(méi)有太多的用武之地了,當(dāng)然從技術(shù)選型的角度看,你仍然可以選擇ORM,但就像關(guān)系型數(shù)據(jù)庫(kù)那樣,它已經(jīng)顯得沒(méi)那么重要了。

      事件溯源(Event Sourcing)

      在某些情況下,我們不僅需要知道對(duì)象的當(dāng)前狀態(tài)是什么,而且還需要知道,對(duì)象經(jīng)歷了哪些路程,才獲得了當(dāng)前這樣的狀態(tài)。Martin Fowler在介紹Event Sourcing的時(shí)候,舉了個(gè)郵包跟蹤(Package Tracking)的例子。在經(jīng)典的DDD實(shí)踐中,我們只能通過(guò)Shipment.Location來(lái)獲得郵包的當(dāng)前位置,卻沒(méi)辦法獲得郵包經(jīng)歷過(guò)哪些地址而最終到達(dá)當(dāng)前的地址。

      為了使我們的業(yè)務(wù)系統(tǒng)具有記錄對(duì)象歷史狀態(tài)的能力,我們使用事件驅(qū)動(dòng)的領(lǐng)域模型來(lái)實(shí)現(xiàn)我們的業(yè)務(wù)系統(tǒng)。簡(jiǎn)而言之,就是對(duì)模型對(duì)象狀態(tài)的修改,僅允許通過(guò)事件的途徑實(shí)現(xiàn),外界無(wú)法通過(guò)任何其他途徑修改對(duì)象的狀態(tài)。那么,記錄對(duì)象的狀態(tài)修改歷史,就只需要記錄事件的類(lèi)型以及發(fā)生順序即可,因?yàn)閷?duì)象的狀態(tài)是由領(lǐng)域事件更改的。于是,也就能理解上面所講的為什么在Event Sourcing的實(shí)現(xiàn)中,領(lǐng)域?qū)ο髮⒉辉倬哂泄袑傩?,或者說(shuō),至少不再具有公有的setter屬性。

      當(dāng)對(duì)象的狀態(tài)被修改后,我們可能希望將對(duì)象保存到持久化機(jī)制,這一點(diǎn)與經(jīng)典的DDD實(shí)踐上的考慮是類(lèi)似的。而與之不同的是,現(xiàn)在我們保存的已不再是某個(gè)領(lǐng)域?qū)ο笤谀硞€(gè)時(shí)間點(diǎn)上的狀態(tài),而是促使對(duì)象將其狀態(tài)改變到當(dāng)前點(diǎn)的一系列事件。由此,倉(cāng)儲(chǔ)(Repository)的實(shí)現(xiàn)需要發(fā)生變化,它需要有保存領(lǐng)域事件的功能,同時(shí)還需要有通過(guò)一系列保存的事件數(shù)據(jù),重建聚合根的能力??吹竭@里,你就知道為什么會(huì)有Event Sourcing這個(gè)概念了:所謂Event Sourcing,就是“通過(guò)事件追溯對(duì)象狀態(tài)的起源(與經(jīng)過(guò))”,它允許你通過(guò)記錄下來(lái)的事件,將你的領(lǐng)域模型恢復(fù)到之前任意一個(gè)時(shí)間點(diǎn)。你可能會(huì)興奮地說(shuō):我的領(lǐng)域模型開(kāi)始支持事件回放與模型重建了!

      Event Sourcing讓我們“透過(guò)現(xiàn)象看本質(zhì)”,使我們更進(jìn)一步地了解到“對(duì)象持久化”的具體含義,其實(shí)也就是對(duì)象狀態(tài)的持久化。只不過(guò),Event Sourcing并不是直接保存了對(duì)象的狀態(tài),而是一系列引起狀態(tài)變化的領(lǐng)域事件。

      仍然以上面的更改客戶姓名為例,在引入領(lǐng)域事件與Event Sourcing之后,整個(gè)模型的結(jié)構(gòu)發(fā)生了變化,以下是相關(guān)代碼,僅供參考。

      隱藏行號(hào) 復(fù)制代碼 ? 代碼
      1. [Serializable]
      2. public partial class CustomerCreatedEvent : DomainEvent
      3.  {
      4.     public string UserName { get; set; }
      5.     public string Password { get; set; }
      6.     public string FirstName { get; set; }
      7.     public string LastName { get; set; }
      8.     public DateTime DayOfBirth { get; set; }
      9. }
      10. 
        
      11. [Serializable]
      12. public partial class ChangeNameEvent : DomainEvent
      13.  {
      14.     public string FirstName{get;set;}
      15.     public string LastName{get;set;}
      16. }
      17. 
        
      18. public partial class Customer : SourcedAggregationRoot
      19.  {
      20.     private DateTime dayOfBirth;
      21.     private string userName;
      22.     private string password;
      23.     private string firstName;
      24.     private string lastName;
      25. 
        
      26.     public Customer(string userName, string password, 
      27.         string firstName, string lastName, DateTime dayOfBirth)
      28.     {
      29.         this.RaiseEvent<CustomerCreatedEvent>(new CustomerCreatedEvent
      30.         {
      31.             DayOfBirth = dayOfBirth,
      32.             FirstName = firstName,
      33.             LastName = lastName,
      34.             UserName = userName,
      35.             Password = password
      36.             
      37.         });
      38.     }
      39. 
        
      40.     public void ChangeName(string firstName, string lastName)
      41.     {
      42.         this.RaiseEvent<ChangeNameEvent>(new ChangeNameEvent
      43.         {
      44.             FirstName = firstName,
      45.             LastName = lastName
      46.         });
      47.     }
      48. 
        
      49.     // Handles the ChangeNameEvent by using Reflection
      50.     [Handles(typeof(ChangeNameEvent))]
      51.     private void DoChangeName(ChangeNameEvent e)
      52.     {
      53.         this.firstName = e.FirstName;
      54.         this.lastName = e.LastName;
      55.     }
      56. 
        
      57.     // Handles the CustomerCreatedEvent by using Reflection
      58.     [Handles(typeof(CustomerCreatedEvent))]
      59.     private void DoCreateCustomer(CustomerCreatedEvent e)
      60.     {
      61.         this.firstName = e.FirstName;
      62.         this.lastName = e.LastName;
      63.         this.userName = e.UserName;
      64.         this.password = e.Password;
      65.         this.dayOfBirth = e.DayOfBirth;
      66.     }
      67. }
      68. 
        

      上面的代碼中定義了兩個(gè)Domain Event:CustomerCreatedEvent和ChangeNameEvent。在Customer聚合根的構(gòu)造函數(shù)中,直接觸發(fā)CustomerCreatedEvent以便該事件的訂閱者對(duì)Customer對(duì)象進(jìn)行初始化;而在Customer聚合根的ChangeName方法中,則直接觸發(fā)ChangeNameEvent以便該事件的訂閱者對(duì)Customer的first name和last name作修改。Customer的基類(lèi)SourcedAggregationRoot則在領(lǐng)域事件被觸發(fā)的時(shí)候通過(guò)Reflection機(jī)制獲得內(nèi)部的事件處理函數(shù),并調(diào)用該函數(shù)完成事件處理。在上面的例子中,也就是DoChangeName和DoCreateCustomer這兩個(gè)方法。在這里需要注意的是,類(lèi)似DoChangeName和DoCreateCustomer這樣的事件處理函數(shù)中,僅允許包含對(duì)對(duì)象狀態(tài)的設(shè)置邏輯。因?yàn)槿绻肫渌僮鞯脑挘茈y保證通過(guò)這些操作,對(duì)象的狀態(tài)不會(huì)發(fā)生改變。

      深入思考上面的設(shè)計(jì)會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,也就是當(dāng)模型對(duì)象變得非常龐大,或者隨著時(shí)間的推移,領(lǐng)域事件將變得越來(lái)越多,于是通過(guò)Event Sourcing來(lái)重建聚合根的過(guò)程也會(huì)變得越來(lái)越耗時(shí),因?yàn)槊恳淮螐慕ǘ夹枰獜淖钤绨l(fā)生的事件開(kāi)始。為了解決這個(gè)問(wèn)題,Event Sourcing引入了“快照(Snapshots)”。


      快照(Snapshots)

      Snapshot的設(shè)計(jì)其實(shí)很簡(jiǎn)單。標(biāo)準(zhǔn)的CQRS實(shí)現(xiàn)中,采用“每產(chǎn)生N個(gè)領(lǐng)域事件,則對(duì)對(duì)象做一次Snapshot”的簡(jiǎn)單規(guī)則。設(shè)計(jì)人員其實(shí)可以根據(jù)自己的實(shí)際情況定義N的取值,甚至可以選用特定的Snapshot規(guī)則,以提高對(duì)象重建的效率。當(dāng)需要通過(guò)倉(cāng)儲(chǔ)獲得某一個(gè)聚合根實(shí)體時(shí),倉(cāng)儲(chǔ)會(huì)首先從Snapshot Store中獲得最近一次的快照,然后再在由此快照還原的聚合根實(shí)體上逐個(gè)應(yīng)用快照之后所產(chǎn)生的領(lǐng)域事件,由此大大加速了對(duì)象重建的過(guò)程??煺胀ǔ2捎肎oF Memento模式實(shí)現(xiàn)。請(qǐng)注意:CQRS引入快照的概念僅僅是為了解決對(duì)象重建的效率問(wèn)題,它并不能替代領(lǐng)域事件所能表述的含義。換句話說(shuō),即使引入快照,也不能表示我們能夠?qū)⒖煺罩暗乃惺录氖录鎯?chǔ)(Event Store)中刪除。因?yàn)椋覀冇涗涱I(lǐng)域事件的目的,是為了Event Sourcing,而不是Snapshots。

      image

       

      事件存儲(chǔ)(Event Store)

      通常,事件存儲(chǔ)是一個(gè)關(guān)系型數(shù)據(jù)庫(kù),用來(lái)保存引起領(lǐng)域?qū)ο鬆顟B(tài)更改的所有領(lǐng)域事件。如上所述,在CQRS結(jié)構(gòu)的系統(tǒng)實(shí)現(xiàn)中,數(shù)據(jù)庫(kù)已經(jīng)不再直接保存對(duì)象的當(dāng)前狀態(tài)了,保存的只是引起對(duì)象狀態(tài)發(fā)生變化的領(lǐng)域事件。于是,數(shù)據(jù)庫(kù)的數(shù)據(jù)結(jié)構(gòu)非常單一,就是單純的領(lǐng)域事件數(shù)據(jù)。事件數(shù)據(jù)的寫(xiě)入、讀取都變得非常簡(jiǎn)單高速,根本無(wú)需ORM的介入,直接使用SQL或者存儲(chǔ)過(guò)程操作事件存儲(chǔ)即可,既簡(jiǎn)單又高效。讀到這里,你會(huì)發(fā)現(xiàn),雖然系統(tǒng)是用的一個(gè)稱(chēng)之為Event Store的機(jī)制保存了領(lǐng)域事件,但這個(gè)Event Store已經(jīng)成為了整個(gè)系統(tǒng)數(shù)據(jù)存儲(chǔ)的核心。更進(jìn)一步考慮,Event Store中的事件數(shù)據(jù)是在倉(cāng)儲(chǔ)執(zhí)行“保存”操作時(shí),從領(lǐng)域模型中收集并寫(xiě)入的,也就意味著,最新的、最真實(shí)的數(shù)據(jù)仍然存在于領(lǐng)域模型中,正好符合DDD面向領(lǐng)域的思想,同時(shí)也引出了另一深層次的考慮:In Memory Domain!

       

      回到結(jié)構(gòu)

      在完成對(duì)“對(duì)象狀態(tài)”、“事件溯源(Event Sourcing)”、“快照(Snapshots)”以及“事件存儲(chǔ)(Event Store)”的討論后,我們?cè)賮?lái)看整個(gè)CQRS的結(jié)構(gòu),這樣就顯得更加清楚。上文【CQRS體系結(jié)構(gòu)模式】圖中,用戶操作被分為命令部分(圖中上半部分)和查詢部分(圖中下半部分)。

      1. 用戶與領(lǐng)域?qū)拥慕换?,是以命令的方式進(jìn)行的:用戶通過(guò)Command Service向領(lǐng)域模型發(fā)送命令。Command Service通常被實(shí)現(xiàn)為.NET WCF Service。Command Bus在接收到命令后,將命令指派到命令執(zhí)行器由其負(fù)責(zé)執(zhí)行(可以參考GoF Command模式。TBD: 可以選擇更符合CQRS實(shí)現(xiàn)的其它途徑)。命令執(zhí)行器在執(zhí)行命令時(shí),通過(guò)領(lǐng)域事件更改對(duì)象狀態(tài),并通過(guò)倉(cāng)儲(chǔ)保存領(lǐng)域?qū)ο?。而倉(cāng)儲(chǔ)并非直接將對(duì)象狀態(tài)保存到外部持久化機(jī)制,而僅僅是從領(lǐng)域?qū)ο笾蝎@得已產(chǎn)生的一系列領(lǐng)域事件,并將這些事件保存到Event Store,同時(shí)將事件發(fā)布到事件總線Event Bus
      2. Event Handler可以訂閱Event Bus中的事件,并在事件發(fā)生時(shí)作相關(guān)處理。上文在討論服務(wù)的時(shí)候,有個(gè)例子就是利用基礎(chǔ)結(jié)構(gòu)層服務(wù)發(fā)送SMS消息,在CQRS的體系結(jié)構(gòu)中,我們完全可以在此訂閱Warehouse Transferred事件,并調(diào)用基礎(chǔ)結(jié)構(gòu)層服務(wù)發(fā)送SMS消息。Domain Model完全不知道自己的內(nèi)部事件被觸發(fā)后,會(huì)出現(xiàn)什么情況,而Event Handler則會(huì)處理這些情況(Domain Model與基礎(chǔ)結(jié)構(gòu)層完全解耦)
      3. 在Event Handler中,有一種特殊的Event Handler,稱(chēng)之為Synchronizer或者Denormalizer,其作用就是為了同步“Query Database”。Query Database是為查詢提供數(shù)據(jù)源的存儲(chǔ)機(jī)制,用戶在UI上看到的查詢數(shù)據(jù)均來(lái)源于此數(shù)據(jù)庫(kù)。因此,CQRS不僅分離了用戶操作,而且分離了數(shù)據(jù)源,這樣做的一個(gè)最大的優(yōu)點(diǎn)就是,設(shè)計(jì)人員可以根據(jù)UI的需求來(lái)配置和優(yōu)化Query Database,例如,可以將Query Database設(shè)計(jì)為一張數(shù)據(jù)表對(duì)應(yīng)一個(gè)UI界面,于是,用戶查詢變得非常靈活高效。這里也可以使用DDD中的Repository結(jié)合ORM實(shí)現(xiàn)數(shù)據(jù)讀取,與處于Domain Layer中的Repository不同,這個(gè)Repository就是DDD中所提到的經(jīng)典型倉(cāng)儲(chǔ)了,你可以靈活地使用規(guī)約模式。當(dāng)然,你也可以不使用ORM而直接SQL甚至No SQL,一切取決于用戶需求與技術(shù)選型。我們還可以根據(jù)需要,對(duì)Synchronizer和Denormalizer的實(shí)現(xiàn)采用緩存,比如,對(duì)于無(wú)需實(shí)時(shí)更新的內(nèi)容,可以每捕獲N個(gè)事件同步一次Query Database,或者當(dāng)有客戶端query請(qǐng)求時(shí),再做一次同步,這也是提高效率的一種有效方法
      4. 用戶UI通過(guò)Data Proxy獲得查詢結(jié)果數(shù)據(jù),WCF將數(shù)據(jù)以DTO的形式發(fā)送給客戶端

      總結(jié)

      本文介紹了CQRS模式的基本結(jié)構(gòu),并對(duì)其中一些重要概念作了注釋?zhuān)彩俏以趯?shí)踐和思考當(dāng)中總結(jié)出來(lái)的內(nèi)容(PS:轉(zhuǎn)載請(qǐng)注明出處)。學(xué)習(xí)過(guò)DDD而剛剛開(kāi)始CQRS的朋友,在閱讀一些資料的時(shí)候勢(shì)必會(huì)感到疑惑,希望本文能夠幫助到這些朋友。比如最開(kāi)始閱讀的時(shí)候,我也不知道為什么一定要通過(guò)領(lǐng)域事件去更改對(duì)象狀態(tài),而不是在對(duì)象狀態(tài)變更的時(shí)候,去觸發(fā)領(lǐng)域事件,因?yàn)楫?dāng)時(shí)我仍然希望能夠在Domain Model中方便地使用getter/setter,我當(dāng)時(shí)也希望能夠讓Domain Model同時(shí)適應(yīng)于經(jīng)典DDD和CQRS架構(gòu)。在經(jīng)過(guò)多次嘗試后發(fā)現(xiàn),這種做法是不合理、不可取的,也正如Udi Dahan所說(shuō):CQRS是一種模式,既然是模式,就是用來(lái)解決特定問(wèn)題的。

      還是一句老話:視需求而定。不要因?yàn)镃QRS所以CQRS。雖然可以很大程度地提升系統(tǒng)性能,雖然可以使系統(tǒng)具有auditing的能力,雖然可以實(shí)現(xiàn)Domain-Centralized,雖然可以讓數(shù)據(jù)存儲(chǔ)變得更加簡(jiǎn)單,雖然給我們提供了很多技術(shù)選型的機(jī)會(huì),但是,CQRS也有很多不足點(diǎn),比如結(jié)構(gòu)實(shí)現(xiàn)較繁雜,數(shù)據(jù)同步穩(wěn)定性難以得到保證,事件溯源(Event Sourcing)出錯(cuò)時(shí),模型對(duì)象狀態(tài)的恢復(fù)等等。還是引用Udi Dahan的一句話:簡(jiǎn)單,但不容易!

      posted @ 2010-08-02 11:16  dax.net  閱讀(20726)  評(píng)論(34)    收藏  舉報(bào)
      主站蜘蛛池模板: 精品久久久久无码| 遂平县| 久久羞羞色院精品全部免费| 中文字幕日韩精品有码视频 | 欧美综合自拍亚洲综合图 | 泽库县| 自拍偷拍一区二区三区四| 国产福利社区一区二区| 国产日韩一区二区四季| 熟女人妻aⅴ一区二区三区电影| 亚洲中文字幕无码久久精品1| 日韩无矿砖一线二线卡乱| аⅴ天堂国产最新版在线中文| 国产精品久久久久久福利| 维西| 国产精品中文字幕久久| 亚洲av成人午夜福利| 成人影片麻豆国产影片免费观看| 亚洲首页一区任你躁xxxxx| 国产成人a在线观看视频| 自拍第一区视频在线观看| 日本特黄特黄刺激大片| jizzjizz日本高潮喷水| 国产va免费精品观看精品| A三级三级成人网站在线视频| 精品国产污污免费网站入口| 午夜福利理论片高清在线| 色综合色狠狠天天综合网| 亚洲另类激情专区小说图片| 亚洲第一人伊伊人色综合| 97人人添人澡人人爽超碰| 久热这里只精品99国产6-99RE视…| 午夜一区欧美二区高清三区| 亚洲AV无码破坏版在线观看| 国产精品久久国产丁香花| 亚洲一区二区偷拍精品| 亚洲日韩久热中文字幕| 俄罗斯美女真人性做爰| 亚洲一区二区三区四区| 成人永久性免费在线视频| 久久一区二区中文字幕|