我正在实施CQRS,我对查询的查询速度有多困惑.我也搜索了它,但由于CQRS的各种风味,我没有得到任何适当的解决方案.也许我在这里做错了什么?这是我的代码和各自的查询.
class User {
public int Id { get; set; }
public string Username { get; set; }
public string Status { get; set; }
public string Role { get; set; }
// ...
}
Run Code Online (Sandbox Code Playgroud)
我想通过用户名找到用户,所以我已经为它编写了查询
abstract class Query<TResult> { }
class FindUserByStatusQuery : Query<IEnumerable<User>> {
public string Status;
}
Run Code Online (Sandbox Code Playgroud)
以及它的相应处理程序
interface IQueryHandler<TQuery, TResult> where TQuery : Query<TResult>
{
TResult Handle(TQuery query);
}
class FindUserByStatusQueryHandler : IQueryHandler<FindUserByStatusQuery, IEnumerable<User>>
{
public IEnumerable<User> Handle(FindUsersByAcountStatusQuery query)
{
using (Entities db = new Entities()) …
Run Code Online (Sandbox Code Playgroud) 如果我实现CQRS和事件源,那么假设数据的最终存储(读取存储)在RDBMS中,那么如何保持数据的完整性和一致性?
如果发布事件但由于违反检查或缺少FK引用而RDBMS拒绝从该事件派生的数据怎么办?
我只是从DDD开始,目前正试图掌握用它做不同事情的方法.我正在尝试使用CQRS使用异步事件(没有事件源)来设计它.目前我坚持使用命令验证.我已经读过这个问题:在域驱动设计中进行验证,但是,没有一个答案似乎涵盖了不同聚合根的复杂验证.
假设我有这些聚合根:
这是用例:
可以提交折扣订单.折扣顺序中的每个新折扣期不应与任何BillCycles重叠.在一项服务上,不能同时激活两种相同类型的折扣.
基本上,在CRUD风格中使用Hibernate,这看起来类似于(java代码,但问题与语言无关):
public class DiscountProcessor {
...
@Transactional
public void processOrder(long orderId) {
DiscOrder order = orderDao.get(orderId);
BillCycle[] cycles = billCycleDao.getAll();
for (OrderItem item : order.getItems()) {
//Validate billcycle overlapping
for (BillCycle cycle : cycles) {
if (periodsOverlap(cycle.getPeriod(), item.getPeriod())) {
throw new PeriodsOverlapWithBillCycle(...);
}
}
//Validate discount overlapping
for (Discount d : item.getForService().getDiscounts()) {
if (d.getType() == item.getType() && periodsOverlap(d.getPeriod(), item.getPeriod())) {
throw new PeriodsOverlapWithOtherItems(...);
} …
Run Code Online (Sandbox Code Playgroud) 我是CQRS的初学者并且有一些问题.
背景是我们拥有20世纪80年代的遗留系统.我们希望实现一个瘦框架,供与之通信的新应用程序使用.
我们的想法是使用CQRS来实现这个框架,但我的问题是我们应该如何做到这一点.数据库和底层结构不会改变.
问题是系统和与它的通信非常慢.使用的协议是Telnet,FTP和一些自定义协议.
我Customer
读过需要更新的模型NewOrderEvent
.
有一件事我想理解,我应该在每个事件上更新我的阅读模型.或者我需要重播所有事件并替换读取模型.
我现在正在做的是:
NewOrderEvent
Customer
阅读模型Customer.ApplyEvent(NewOrderEvent)
该更改Customer
状态.Customer
读取模型我错过了什么吗?
使用DDD,CQRS和事件源时,可能会重新发送消息或无序发送消息.
我不太关心命令消息,因为用户会立即知道它是否成功.我关心的是事件.如果将聚合版本号附加到事件中,我们是否可以使操作具有幂等性?例如:
class Person {
public function apply(PersonNameUpdated event) {
if (version_ + 1 != event.version) {
name_ = event.name;
++version_;
}
}
private String name_;
private Integer version_;
}
Run Code Online (Sandbox Code Playgroud) 我有以下型号:
public class Team {
public Guid Id {get; set;}
public string Name {get; set;}
public string League {get; get;}
public int Rating {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
在系统中创建新团队后,我将事件发布TeamCreated
到服务总线:
{
"MessageId": "33909eaf-56a1-4467-a01a-64b94f10490c"
"MessageType": "TeamCreated",
"CreationDate": "20-01-2016",
"Payload": {
"Id": "11111www-56a1-4467-a01a-64b94f000111",
"Name": "Toronto Maple Leafs",
"League": "NHL NorthEast",
"Rating": 100
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,此条目已修改为以下内容:
{
"MessageId": "33909eaf-56a1-4467-a01a-64b94f10490c"
"MessageType": "TeamUpdated",
"CreationDate": "20-01-2016",
"Payload": {
"Id": "11111www-56a1-4467-a01a-64b94f000111",
"Name": "Toronto Maple Leafs",
"League": "NHL NorthEast",
"Rating": 50
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,他更新的消息仍保留所有属性的值,而不仅仅是已更改的属性,即团队的等级.
我的模型,在真实系统中有超过50个属性,我不希望在每个属性更新时为它们创建单独的事件.特别是因为可能是在一次更新中更改了多个属性的情况.
在事件采购架构中是否存在针对此场景的已定义模式?
我创建Web API已有一段时间了,很高兴能够测试CQRS处理程序(由Mediatr管理)而无需接触任何类型的基础架构代码(控制器,requets等)。在执行控制器应该做的事情时非常薄:请求和响应之间的通信:
[HttpGet("requests")]
public async Task<IEnumerable<AbsenceRequest>> GetAbsenceRequests(GetAbsenceRequests.Query query)
{
return await _mediator.Send(query);
}
Run Code Online (Sandbox Code Playgroud)
但是仍然存在我的Handlers测试无法涵盖的情况。这里有几个例子:
ASP.NET Core使请求输入响应输出集成测试非常容易(由于使用了TestServer),我可以在集成测试中介绍这两种情况。
让我困扰的问题是我应该通过发送请求并声明响应来保持Handlers测试还是测试动作。
我真的很喜欢Handler测试。它们很可爱,清晰而且易于编写。测试整个请求的功能要强大得多,但同时它却是一个相对较低级别的方法,因此杂乱无章,您必须处理http和json。
我发现此选择非常令人困惑,并且想知道推荐的方法是什么。
我试图找出如何使用CQRS/ES方法处理复杂域模型.让我们假设我们有例如Order域实体,它处理订单的状态和行为.它有一个Status属性,带有用于在状态之间切换的转换规则(实现状态模式或任何其他类型的状态机).据DDD原理,该逻辑应在Order类(表示订单模型)来实现本身,具有类似的方法approve()
,cancel()
,ship()
等.
看看这种体系结构的不同 公共 示例,结果表明域实体和聚合根是相同的,它处理状态和行为,甚至是自己对事件的预测.这不违反SRP吗?
但我的问题更具体:如果我想处理新命令(并应用新事件),我应该从事件流(即从写模型和写入数据库)重建实体并调用其行为方法(将事件应用于状态)处理业务规则?或者只是处理命令和事件本身,而没有任何写模型实体?
伪代码说明:
class ApproveOrderHandler
{
private EventStore eventStore
// ...
public void handle(ApproveOrder event)
{
Order order = this.eventStore.findById(event.getOrderId()); // getting order projection from event store
order.approve(); // handling business logic
this.eventStore.save(order.releaseEvents()); // save new events (OrderApproved)
}
}
class Order extends AbstractAggregate
{
private Uuid id;
private DateTime takenAt;
private OrderStatus status;
// ...
public void approve()
{
this.status.approve(); // business rules blah blah
this.Apply(new …
Run Code Online (Sandbox Code Playgroud) architecture domain-driven-design business-rules cqrs event-sourcing
我尝试使用axon 配置cqrs和事件源. SeatReseveCreateCommand工作正常.但SeatReserveUpadateCommand无法正常工作.
这是我的SeatReserve 聚合
@Aggregate
public class SeatReserve {
@AggregateIdentifier
private String id;
private String seatid;
private Date date;
@SuppressWarnings("unused")
private SeatReserve() {
}
@CommandHandler
public SeatReserve(SeatReseveCreateCommand seatReseveCreateCommand) {
apply(new SeatReseveCreateEvent(seatReseveCreateCommand.getMyid(), seatReseveCreateCommand.getSeatId(),
seatReseveCreateCommand.getDate()));
}
@CommandHandler
public SeatReserve(SeatReserveUpadateCommand upadateCommand) {
apply(new SeatReserveUpadateEvent(id, upadateCommand.getSeatId()));
}
@EventSourcingHandler
public void on(SeatReseveCreateEvent seatReseveCreateEvent) {
this.id = seatReseveCreateEvent.getId();
this.seatid = seatReseveCreateEvent.getSeatId();
this.date = seatReseveCreateEvent.getDate();
}
@EventSourcingHandler
public void on(SeatReserveChangeEvent upadateEvent) {
seatid = upadateEvent.getSeatId();
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的控制器
@RestController …
Run Code Online (Sandbox Code Playgroud) cqrs ×10
c# ×2
.net ×1
architecture ×1
asp.net-core ×1
axon ×1
idempotent ×1
legacy ×1
mediatr ×1
spring-boot ×1
validation ×1