2014-05-04 27 views
10

我在读Accounting Pattern,并对在CQRS中实施它非常好奇。如何在CQRS中建立银行转帐模型

我觉得AccountingTransaction是一个聚合根,因为它保护不变:

没有钱泄漏,应该是从一个账户转移到另一个。

public class AccountingTransaction { 
    private String sequence; 
    private AccountId from; 
    private AccountId to; 
    private MonetaryAmount quantity; 
    private DateTime whenCharged; 

    public AccountingTransaction(...) { 
     raise(new AccountingEntryBookedEvent(sequence, from, quantity.negate(),...); 
     raise(new AccountingEntryBookedEvent(sequence, to, quantity,...); 
    } 
} 

将AccountingTransaction添加到其存储库时。它发布了几个AccountingEntryBookedEvent,用于更新查询端相应帐户的余额。

每个db事务更新一个聚合根,最终一致性,到目前为止非常好。

但是如果某些账户应用转账限制,例如不能将更多的数量转移到当前余额?我可以使用查询端来获取帐户的余额,但是我担心查询端的数据是陈旧的。

public class TransferApplication { 
    public void transfer(...) { 
     AccountReadModel from = accountQuery.findBy(fromId); 
     AccountReadModel to = accountQuery.findBy(toId); 
     if (from.balance() > quantity) { 
      //create txn 
     } 
    } 
} 

我应该在命令端模拟帐户吗?我必须更新每个db事务至少三个聚合根(从/到帐户和帐户txn)。

public class TransferApplication { 
    public void transfer(...) { 
     Account from = accountRepository.findBy(fromId); 
     Account to = accountRepository.findBy(toId); 
     Transaction txn = new Transaction(from, to, quantity); 
     //unit or work locks and updates all three aggregates 
    } 
} 

public class AccountingTransaction { 
    public AccountingTransaction(...) { 
     if (from.permit(quantity) { 
      from.debit(quantity); 
      to.credit(quantity); 
      raise(new TransactionCreatedEvent(sequence, from, to, quantity,...); 
     } 
    } 
} 
+0

您是否想要使用DDD进行银行应用? – Developer

+0

@Singh谢谢你的评论。是的,DDD与CQRS。 – Hippoom

+0

我有一个关于银行应用程序的项目。你想要吗? – Developer

回答

3

有一些用例不允许最终的一致性。 CQRS很好,但数据可能需要100%一致。 CQRS不暗示/要求最终的一致性。

但是,交易/域模型存储将是一致的,并且由于代表当前状态,所以余额将在中保持一致。在这种情况下,无论如何,交易都会失败,而不管查询方面的不一致。虽然100%一致的方法可能会更好,但这将会带来一些奇怪的用户体验。

3

我记得这一点,但M福勒使用与域事件相比事件的不同含义。他使用'错误'的术语,因为我们可以在他'事件'的定义中识别一个命令。所以他基本上是在谈论命令,而域名事件是发生的事情,它永远不会改变。

我可能并没有完全理解福勒所指的,但我会以不同的方式对事物进行建模,更确切地说尽可能地接近域。我们不能简单地提取可以永远应用于任何金融应用程序的模式,小细节可能会改变概念的含义。

在OP的例子中,我想说我们可以有一个非显式的'交易':我们需要一个账户借记一个金额和另一个信用金额相同的金额。我认为最简单的方法就是通过一个传奇来实现它。

Debit_Account_A - > Account_A_Debited - > Credit_Account_B-> Account_B_Credited =交易已完成。

这应该发生在几秒钟内最多秒,这将足以更新读取模型。人类和浏览器比几秒钟慢。而用户知道打F5或等待几分钟/小时。我不会太在意读取模型的准确性。

如果交易是明确的,即域具有交易概念,并且业务确实存储完全不同的交易。但即使在这种情况下,交易可能会由多个帐户ID和一些金额以及可能已完成的标志来定义。但是,在这一点上毫无意义的继续,因为它真的取决于域的定义和用例。