强调事件的架构中的命令和事件有什么区别? 我能看到的唯一区别是命令通常由系统外部的angular色来源/调用,而事件似乎是由系统中的处理程序和其他代码提供的。 但是,在我看到的许多示例应用程序中,它们具有不同(但function相似)的接口。
我对CQRS的看法是严格按照你的命令不返回任何东西(返回types无效),所以我的例子是非常简单的:如何创build一些东西时检索ID? 例如,在创build信用卡交易时,返回交易ID似乎相当重要,或者在创build客户时,如果您获得了您创build的客户或客户ID,那么浏览器可以自动导航到该客户页面例如。 一种解决scheme可能是首先要求一个ID,然后用这个ID创build客户或交易,但看起来很奇怪。 有没有人有这方面的经验或现在应该如何以最有效的方式来完成? 也许我误解了一些东西?
危险…史密斯博士危险…前面的哲学职位 这篇文章的目的是为了确定是否将validation逻辑放在我的域实体之外(实际上是聚合根)实际上给了我更多的灵活性,或者它是kamikaze代码 基本上我想知道是否有更好的方法来validation我的域实体。 这是我打算这样做,但我希望你的意见 我考虑的第一个方法是: class Customer : EntityBase<Customer> { public void ChangeEmail(string email) { if(string.IsNullOrWhitespace(email)) throw new DomainException(“…”); if(!email.IsEmail()) throw new DomainException(); if(email.Contains(“@mailinator.com”)) throw new DomainException(); } } 我实际上不喜欢这个validation,因为即使当我将validation逻辑封装在正确的实体中时,这违反了打开/closures原则(打开以进行扩展,但是closures以进行修改),并且我发现违反这个原则,代码维护变成当应用程序复杂化时,真正的痛苦。 为什么? 由于领域规则的变化比我们想要承认的要多,而且如果规则隐藏在这样一个实体中,他们很难testing,很难阅读,很难维护,但是为什么我不喜欢这个方法是:如果validation规则改变,我必须来编辑我的域实体。 这是一个非常简单的例子,但在RL中validation可能会更复杂 所以遵循Udi Dahan的哲学, 明确的angular色以及Eric Evans在蓝皮书中的build议,接下来的尝试是实现规范模式,像这样 class EmailDomainIsAllowedSpecification : IDomainSpecification<Customer> { private INotAllowedEmailDomainsResolver invalidEmailDomainsResolver; public bool IsSatisfiedBy(Customer customer) { return !this.invalidEmailDomainsResolver.GetInvalidEmailDomains().Contains(customer.Email); } } 但是后来我意识到,为了遵循这种方法,我必须首先对实体进行变异,以便传递被赋值的值 […]
作为研究与项目一起使用的CQRS的一部分,我碰到了Axon框架 ,我想知道是否有人有任何真实的生活经验。 要清楚的是,我正在询问框架,而不是CQRS作为一种架构模式。 我的项目已经使用了Spring和Spring Integration,它非常适合Axon自己的需求,但在我投入大量时间之前,我想知道是否有人有第一手的经验。 特别是我感兴趣的是我可能从文档中看不到的陷阱。
我们以一个简单的“账户注册”为例,这里是stream程: 用户访问网站 点击“注册”button并填写表格,点击“保存”button MVC控制器:通过从ReadModel读取validation用户名的唯一性 RegisterCommand:再次validation用户名唯一性(这是问题) 当然,我们可以通过读取MVC控制器中的ReadModel来validationUserName的唯一性,以提高性能和用户体验。 但是, 我们仍然需要在RegisterCommand中再次validation唯一性 ,显然,我们不应该访问命令中的ReadModel。 如果我们不使用事件采购,我们可以查询领域模型,所以这不成问题。 但是如果我们使用Event Sourcing,我们无法查询域模型,那么我们如何validationRegisterCommand中的UserName唯一性? 注意:用户类有一个Id属性,UserName不是User类的关键属性。 使用事件采购时,我们只能通过Id获取域对象。 顺便说一句:在要求中,如果input的用户名已被占用,网站应该向访问者显示错误信息“对不起,用户名XXX不可用”。 显示一条消息,例如“我们正在创build您的帐户,请等待,我们将通过电子邮件向您发送注册结果”,这是不能接受的。 有任何想法吗? 非常感谢! [UPDATE] 一个更复杂的例子: 需求: 下订单时,系统应该检查客户的订单历史,如果他是一个有价值的客户(如果客户在过去一年每月至less有10个订单,他是有价值的),我们使订单10%的折扣。 执行: 我们创buildPlaceOrderCommand,并在命令中,我们需要查询订购历史logging,看看客户是否有价值。 但是我们该怎么做呢? 我们不应该在命令中访问ReadModel! 正如Mikael 所说 ,我们可以在帐户注册的例子中使用补偿命令,但是如果我们在这个sorting的例子中也使用补偿命令,它会太复杂,代码可能太难维护。
我正在寻找一些深入的CQRS的例子,并有一套合理的unit testing。 另外,如果有人知道一些CQRS屏幕录像,那么这将非常方便。 我已经知道这些例子 CQRS信息 超级简单的CQRS
如果我正在使用RDBMS(例如SQL Server)来存储事件源数据,模式可能是什么样子? 我已经看到抽象意义上谈到的一些变化,但没有具体的。 例如,假设有一个“产品”实体,并且对该产品的更改可以以价格,成本和描述的forms出现。 我很困惑我是否会: 有一个“ProductEvent”表,其中包含产品的所有字段,其中每个更改意味着该表中的新logging,以及适当时候的“谁,什么,何处,何处,何时以及如何”。 当成本,价格或描述发生变化时,会添加一个新的行来表示产品。 将产品成本,价格和说明存储在与外部关系关联的“产品”表中的单独表中。 对这些属性进行更改时,请根据需要使用WWWWWH编写新行。 将“WWWWWH”和表示事件的序列化对象存储在“ProductEvent”表中,这意味着事件本身必须在我的应用程序代码中被加载,反序列化并重新播放,以重build给定产品的应用程序状态。 特别是我担心上面的选项2。 极端地说,产品表几乎是每个属性一个表,在哪里加载给定产品的应用程序状态将需要从每个产品事件表加载该产品的所有事件。 这张桌子爆炸味道对我来说是错误的。 我确信“这要看情况”,虽然没有一个“正确的答案”,但我试图去了解什么是可以接受的,什么是完全不能接受的。 我也知道NoSQL在这里可以提供帮助,在这里可以根据聚合根存储事件,这意味着只有一个数据库请求来获取事件来重build对象,但是我们没有使用NoSQL数据库这一刻,我感觉周围的替代品。
虽然我以前碰到过Kafka ,但是最近才意识到Kafka也许可以作为一个CQRS 事件库的基础。 卡夫卡支持的主要观点之一是: 事件捕获/存储,当然是所有的HA。 Pub / Sub架构 能够重放事件日志,允许新用户在事后注册系统。 无可否认,我并不是100%熟悉CQRS /事件采购,但这似乎与事件应该是非常接近的。 有趣的是:我真的无法find关于卡夫卡被用作事件库的很多东西,所以也许我一定会错过一些东西。 那么,卡夫卡有什么遗漏,因为它是一个很好的事件? 它会工作吗? 使用它生产? 对洞察力,链接等感兴趣 基本上,根据系统所接收的事务/事件来保存系统的状态,而不是仅保存通常所做的系统的当前状态/快照。 (把它看作会计中的一个总账:所有的交易最终总计到最终的状态)这允许各种各样的很酷的事情,但只是在提供的链接上阅读。
我有一个BusinessLayer项目,它具有以下代码。 域对象是FixedBankAccount(它实现了IBankAccount)。 该存储库是作为域对象的公共属性,并作为接口成员。 如何重构它,使存储库不会是一个接口成员 ? 域对象(FixedBankAccount)直接使用存储库来存储数据。 这是否违反单一责任原则? 如何纠正? 注意:存储库模式是使用LINQ to SQL实现的。 编辑 下面给出的代码是更好的方法吗? https://codereview.stackexchange.com/questions/13148/is-it-good-code-to-satisfy-single-responsibility-principle 码 public interface IBankAccount { RepositoryLayer.IRepository<RepositoryLayer.BankAccount> AccountRepository { get; set; } int BankAccountID { get; set; } void FreezeAccount(); } public class FixedBankAccount : IBankAccount { private RepositoryLayer.IRepository<RepositoryLayer.BankAccount> accountRepository; public RepositoryLayer.IRepository<RepositoryLayer.BankAccount> AccountRepository { get { return accountRepository; } set { accountRepository […]