Exemplo n.º 1
0
        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);
        }