From 3d3f46f0b1e6af10d99210524711d063405a190c Mon Sep 17 00:00:00 2001 From: meysamhadeli Date: Sun, 12 Jun 2022 23:05:23 +0430 Subject: [PATCH] add optimistic concurrency --- src/BuildingBlocks/Domain/Model/Aggregate.cs | 4 +-- src/BuildingBlocks/Domain/Model/IAggregate.cs | 26 +++++++-------- src/BuildingBlocks/EFCore/AppDbContextBase.cs | 2 ++ .../Events/AggregateEventSourcing.cs | 32 +++++++++++++++++++ .../Events/IAggregateEventSourcing.cs | 19 +++++++++++ .../Repository/EventStoreDBRepository.cs | 7 ++-- .../Repository/RepositoryExtensions.cs | 5 +-- .../src/Booking/Booking/Models/Booking.cs | 3 +- 8 files changed, 73 insertions(+), 25 deletions(-) create mode 100644 src/BuildingBlocks/EventStoreDB/Events/AggregateEventSourcing.cs create mode 100644 src/BuildingBlocks/EventStoreDB/Events/IAggregateEventSourcing.cs diff --git a/src/BuildingBlocks/Domain/Model/Aggregate.cs b/src/BuildingBlocks/Domain/Model/Aggregate.cs index eed9ce2..f2e3b17 100644 --- a/src/BuildingBlocks/Domain/Model/Aggregate.cs +++ b/src/BuildingBlocks/Domain/Model/Aggregate.cs @@ -25,9 +25,7 @@ namespace BuildingBlocks.Domain.Model return dequeuedEvents; } - public virtual void When(object @event) { } - - public long Version { get; protected set; } = -1; + public long Version { get; set; } = -1; public TId Id { get; protected set; } } diff --git a/src/BuildingBlocks/Domain/Model/IAggregate.cs b/src/BuildingBlocks/Domain/Model/IAggregate.cs index f9178ff..9725ed2 100644 --- a/src/BuildingBlocks/Domain/Model/IAggregate.cs +++ b/src/BuildingBlocks/Domain/Model/IAggregate.cs @@ -1,19 +1,15 @@ -using BuildingBlocks.Domain.Event; -using BuildingBlocks.EventStoreDB.Events; +using BuildingBlocks.Domain.Event; -namespace BuildingBlocks.Domain.Model +namespace BuildingBlocks.Domain.Model; + +public interface IAggregate : IEntity { - public interface IAggregate : IProjection, IEntity - { - IReadOnlyList DomainEvents { get; } - IEvent[] ClearDomainEvents(); - long Version { get; } - } - - public interface IAggregate : IAggregate - { - T Id { get; } - } + IReadOnlyList DomainEvents { get; } + IEvent[] ClearDomainEvents(); + long Version { get; set; } } - +public interface IAggregate : IAggregate +{ + T Id { get; } +} diff --git a/src/BuildingBlocks/EFCore/AppDbContextBase.cs b/src/BuildingBlocks/EFCore/AppDbContextBase.cs index 7765222..dbe629e 100644 --- a/src/BuildingBlocks/EFCore/AppDbContextBase.cs +++ b/src/BuildingBlocks/EFCore/AppDbContextBase.cs @@ -111,11 +111,13 @@ public abstract class AppDbContextBase : DbContext, IDbContext case EntityState.Added: entry.Entity.CreatedBy = userId; entry.Entity.CreatedAt = DateTime.Now; + entry.Entity.Version++; break; case EntityState.Modified: entry.Entity.LastModifiedBy = userId; entry.Entity.LastModified = DateTime.Now; + entry.Entity.Version++; break; case EntityState.Deleted: diff --git a/src/BuildingBlocks/EventStoreDB/Events/AggregateEventSourcing.cs b/src/BuildingBlocks/EventStoreDB/Events/AggregateEventSourcing.cs new file mode 100644 index 0000000..c55c4eb --- /dev/null +++ b/src/BuildingBlocks/EventStoreDB/Events/AggregateEventSourcing.cs @@ -0,0 +1,32 @@ +using BuildingBlocks.Domain.Event; +using BuildingBlocks.Domain.Model; + +namespace BuildingBlocks.EventStoreDB.Events +{ + public abstract class AggregateEventSourcing : Entity, IAggregateEventSourcing + { + private readonly List _domainEvents = new(); + public IReadOnlyList DomainEvents => _domainEvents.AsReadOnly(); + + public void AddDomainEvent(IDomainEvent domainEvent) + { + _domainEvents.Add(domainEvent); + } + + public IEvent[] ClearDomainEvents() + { + IEvent[] dequeuedEvents = _domainEvents.ToArray(); + + _domainEvents.Clear(); + + return dequeuedEvents; + } + + public virtual void When(object @event) { } + + public long Version { get; protected set; } = -1; + + public TId Id { get; protected set; } + } +} + diff --git a/src/BuildingBlocks/EventStoreDB/Events/IAggregateEventSourcing.cs b/src/BuildingBlocks/EventStoreDB/Events/IAggregateEventSourcing.cs new file mode 100644 index 0000000..42ceccd --- /dev/null +++ b/src/BuildingBlocks/EventStoreDB/Events/IAggregateEventSourcing.cs @@ -0,0 +1,19 @@ +using BuildingBlocks.Domain.Event; +using BuildingBlocks.Domain.Model; + +namespace BuildingBlocks.EventStoreDB.Events +{ + public interface IAggregateEventSourcing : IProjection, IEntity + { + IReadOnlyList DomainEvents { get; } + IEvent[] ClearDomainEvents(); + long Version { get; } + } + + public interface IAggregateEventSourcing : IAggregateEventSourcing + { + T Id { get; } + } +} + + diff --git a/src/BuildingBlocks/EventStoreDB/Repository/EventStoreDBRepository.cs b/src/BuildingBlocks/EventStoreDB/Repository/EventStoreDBRepository.cs index 712b78d..6d26cc2 100644 --- a/src/BuildingBlocks/EventStoreDB/Repository/EventStoreDBRepository.cs +++ b/src/BuildingBlocks/EventStoreDB/Repository/EventStoreDBRepository.cs @@ -1,11 +1,10 @@ -using BuildingBlocks.Domain.Model; -using BuildingBlocks.EventStoreDB.Events; +using BuildingBlocks.EventStoreDB.Events; using BuildingBlocks.EventStoreDB.Serialization; using EventStore.Client; namespace BuildingBlocks.EventStoreDB.Repository; -public interface IEventStoreDBRepository where T : class, IAggregate +public interface IEventStoreDBRepository where T : class, IAggregateEventSourcing { Task Find(long id, CancellationToken cancellationToken); Task Add(T aggregate, CancellationToken cancellationToken); @@ -13,7 +12,7 @@ public interface IEventStoreDBRepository where T : class, IAggregate Task Delete(T aggregate, long? expectedRevision = null, CancellationToken cancellationToken = default); } -public class EventStoreDBRepository: IEventStoreDBRepository where T : class, IAggregate +public class EventStoreDBRepository: IEventStoreDBRepository where T : class, IAggregateEventSourcing { private readonly EventStoreClient eventStore; diff --git a/src/BuildingBlocks/EventStoreDB/Repository/RepositoryExtensions.cs b/src/BuildingBlocks/EventStoreDB/Repository/RepositoryExtensions.cs index c2c0343..08466ae 100644 --- a/src/BuildingBlocks/EventStoreDB/Repository/RepositoryExtensions.cs +++ b/src/BuildingBlocks/EventStoreDB/Repository/RepositoryExtensions.cs @@ -1,4 +1,5 @@ using BuildingBlocks.Domain.Model; +using BuildingBlocks.EventStoreDB.Events; using BuildingBlocks.Exception; namespace BuildingBlocks.EventStoreDB.Repository; @@ -9,7 +10,7 @@ public static class RepositoryExtensions this IEventStoreDBRepository repository, long id, CancellationToken cancellationToken - ) where T : class, IAggregate + ) where T : class, IAggregateEventSourcing { var entity = await repository.Find(id, cancellationToken); @@ -22,7 +23,7 @@ public static class RepositoryExtensions Action action, long? expectedVersion = null, CancellationToken cancellationToken = default - ) where T : class, IAggregate + ) where T : class, IAggregateEventSourcing { var entity = await repository.Get(id, cancellationToken); diff --git a/src/Services/Booking/src/Booking/Booking/Models/Booking.cs b/src/Services/Booking/src/Booking/Booking/Models/Booking.cs index 3f127dc..a6c02a4 100644 --- a/src/Services/Booking/src/Booking/Booking/Models/Booking.cs +++ b/src/Services/Booking/src/Booking/Booking/Models/Booking.cs @@ -1,10 +1,11 @@ using Booking.Booking.Events.Domain; using Booking.Booking.Models.ValueObjects; using BuildingBlocks.Domain.Model; +using BuildingBlocks.EventStoreDB.Events; namespace Booking.Booking.Models; -public class Booking : Aggregate +public class Booking : AggregateEventSourcing { public Booking() {