NestJs CQRS - aggregate setup with co existing TypeORM entities
因此这里有一个官方示例
https://github.com/kamilmysliwiec/nest-cqrs-example
,我尝试为三个简单功能创建自己的功能:
- 获取所有用户
- 通过ID获取一个用户
- 创建一个用户
我正在使用TypeORM,并且有一个基本的User实体。因此,根据官方示例代码,我创建了一个用于创建用户的命令处理程序(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @CommandHandler(CreateUserCommand) export class CreateUserHandler implements ICommandHandler<CreateUserCommand> { constructor( private readonly usersRepository: UsersRepository, private readonly eventPublisher: EventPublisher, ) {} public async execute(command: CreateUserCommand): Promise<void> { const createdUser: User = await this.usersRepository.createUser( command.username, command.password, ); // const userAggregate: UserAggregate = this.eventPublisher.mergeObjectContext( // createdUser, // ); // userAggregate.doSomething(createdUser); // userAggregate.commit(); } } |
它所做的只是将一个新的用户实体保留到数据库中。但是我现在没有得到的是如何处理用户集合。合并对象上下文时,我无法传递创建的用户实体。而且我不知道聚合应该处理哪个逻辑。因此,基于此用户集合(
1 2 3 4 5 6 7 8 9 10 11 | export class User extends AggregateRoot { constructor(private readonly id: string) { super(); } public doSomething(user: UserEntity): void { // do something here? this.apply(new UserCreatedEvent(user)); } } |
我知道我可以提出该事件,创建一个新用户并将其推送到历史记录中。但这是它唯一负责的吗?
那么我该如何设置用户集合并正确创建用户处理程序?
传入创建的实体时,出现类似
的错误
Argument of type 'User' is not assignable to parameter of type 'AggregateRoot'. Type 'User' is missing the following properties from
type 'AggregateRoot': autoCommit, publish, commit, uncommit, and 7
more.ts(2345)
之所以有意义,是因为TypeORM实体扩展了
更新:到临时存储库的链接已删除,因为它不再存在。
您提到的此
回复评论,因为评论有残障
而不是:
1 2 3 4 5 6 7 8 9 | const createdUser: User = await this.usersRepository.createUser( command.username, command.password, ); const userAggregate: UserAggregate = this.eventPublisher.mergeObjectContext( createdUser, ); userAggregate.raiseUserCreatedEvent(createdUser); |
做
1 2 3 4 5 6 7 | const userAggregate: UserAggregate = this.eventPublisher.mergeObjectContext( await this.usersRepository.createUser( command.username, command.password, ) ); userAggregate.raiseUserCreatedEvent(); |
然后在
1 2 3 | public raiseUserCreatedEvent(): void { this.apply(new UserCreatedEvent(this)); } |
btw,如果要删除以下行中的
1 | const createdUser: User = await this.usersRepository.createUser( |
它可能会起作用,因为您不必在这里设置类型,这是不必要的,typescript可以自己猜测类型,因此在这种情况下您不必自己做。
@cojack给出的答案假定您的TypeORM实体定义和CQRS AggregateRoot由同一类定义。许多NestJS CQRS项目都是这样实现的(尽管这不是最佳实践,并且违反了单一职责原则。并且您的域类不应与数据库具有依赖关系)。
正如您在注释中指出的那样,如果您的TypeORM定义必须从
但是没有必要这样做。在命令处理程序中,您可以调用
然后在
有关此示例,请参见nestjs-rest-cqrs-example项目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @CommandHandler(CreateAccountCommand) export class CreateAccountCommandHandler implements ICommandHandler<CreateAccountCommand> { constructor( @InjectRepository(AccountEntity) private readonly repository: AccountRepository, private readonly publisher: EventPublisher, ) {} async execute(command: CreateAccountCommand): Promise<void> { // Validation of the command (check if account with this email already exists). await this.repository.findOne({ where: [{ email: command.email }]}).then((item) => { if (item) throw new HttpException('Conflict', HttpStatus.CONFLICT); }); const { name, email, password } = command; // Create the account via the repository. The TypeORM entity is returned. const result = await this.repository.save(new CreateAccountMapper(name, email, bcrypt.hashSync(password))); const account: Account = this.publisher.mergeObjectContext( // Create the AggregateRoot entity to be passed to the context. new Account(result.id, name, email, result.password, result.active), ); account.commit(); } } |
就聚合根中的事件而言,该项目并没有做太多事情,但我希望您能明白。
有许多方法可以布置CQRS模型以及添加逻辑的位置。有关更复杂但布局合理的示例,请参见Adrian Lopez的Daruma Backend。
1 | const userAggregate = this.eventPublisher.mergeObjectContext(new User(createdUser.id); |