public async Task <AggregateApplicationResult> ApplyEventAsync(BaseEvent evt) { // Lets have a constraint for item Name uniqueness ItemAggregate aggregate; BaseItemEvent itemEvent; switch (evt) { case ItemCreatedEvent created: var itemsWithSameName = await aggregatesRepository.GetByNameAsync(created.Name); if (itemsWithSameName.Any(x => x.LastEvent != null && !(x.LastEvent is ItemDeletedEvent))) { return(new ItemAlreadyExistsApplicationResult("Item with the same name already exists")); } aggregate = new ItemAggregate(created.ItemId); itemEvent = created; break; case ItemDeletedEvent deleted: aggregate = await aggregatesRepository.GetByIdAsync(deleted.ItemId); if (aggregate == null || aggregate.LastEvent == null) { return(new ItemNotFoundApplicationResult()); } if (aggregate.LastEvent is ItemDeletedEvent) { // It is already deleted return(new SuccessAggregateApplicationResult()); } itemEvent = deleted; break; case ItemUpdatedEvent updated: aggregate = await aggregatesRepository.GetByIdAsync(updated.ItemId); if (aggregate == null || aggregate.LastEvent == null || aggregate.LastEvent is ItemDeletedEvent) { return(new ItemNotFoundApplicationResult()); } if (aggregate.LastEvent is ItemUpdatedEvent lastUpdated && lastUpdated.Name.Equals(updated.Name)) { // This aggregate has already got this name return(new SuccessAggregateApplicationResult()); } // Looking for another aggregate with this name var itemsWithSameNameForUpdate = await aggregatesRepository.GetByNameAsync(updated.Name); if (itemsWithSameNameForUpdate.Any(x => x.LastEvent != null && !(x.LastEvent is ItemDeletedEvent))) { return(new ItemAlreadyExistsApplicationResult("Item with the same name already exists")); } itemEvent = updated; break; default: return(new FailedAggregateApplicationResult($"Specified event type {evt.GetType().Name} is not supported")); } var applicationResult = aggregate.ApplyEvent(itemEvent); switch (applicationResult) { case SuccessAggregateApplicationResult success: // This method might be a root specific, because of several aggregate repositories might be impacted by one event this.stagedAggregates.Add(aggregate); break; } return(applicationResult); }