mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-05-03 11:21:53 +08:00
add optimistic concurrency
This commit is contained in:
parent
ed931ae0f2
commit
3d3f46f0b1
@ -25,9 +25,7 @@ namespace BuildingBlocks.Domain.Model
|
|||||||
return dequeuedEvents;
|
return dequeuedEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void When(object @event) { }
|
public long Version { get; set; } = -1;
|
||||||
|
|
||||||
public long Version { get; protected set; } = -1;
|
|
||||||
|
|
||||||
public TId Id { get; protected set; }
|
public TId Id { get; protected set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
using BuildingBlocks.Domain.Event;
|
using BuildingBlocks.Domain.Event;
|
||||||
using BuildingBlocks.EventStoreDB.Events;
|
|
||||||
|
|
||||||
namespace BuildingBlocks.Domain.Model
|
namespace BuildingBlocks.Domain.Model;
|
||||||
{
|
|
||||||
public interface IAggregate : IProjection, IEntity
|
public interface IAggregate : IEntity
|
||||||
{
|
{
|
||||||
IReadOnlyList<IDomainEvent> DomainEvents { get; }
|
IReadOnlyList<IDomainEvent> DomainEvents { get; }
|
||||||
IEvent[] ClearDomainEvents();
|
IEvent[] ClearDomainEvents();
|
||||||
long Version { get; }
|
long Version { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAggregate<out T> : IAggregate
|
public interface IAggregate<out T> : IAggregate
|
||||||
{
|
{
|
||||||
T Id { get; }
|
T Id { get; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -111,11 +111,13 @@ public abstract class AppDbContextBase : DbContext, IDbContext
|
|||||||
case EntityState.Added:
|
case EntityState.Added:
|
||||||
entry.Entity.CreatedBy = userId;
|
entry.Entity.CreatedBy = userId;
|
||||||
entry.Entity.CreatedAt = DateTime.Now;
|
entry.Entity.CreatedAt = DateTime.Now;
|
||||||
|
entry.Entity.Version++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EntityState.Modified:
|
case EntityState.Modified:
|
||||||
entry.Entity.LastModifiedBy = userId;
|
entry.Entity.LastModifiedBy = userId;
|
||||||
entry.Entity.LastModified = DateTime.Now;
|
entry.Entity.LastModified = DateTime.Now;
|
||||||
|
entry.Entity.Version++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EntityState.Deleted:
|
case EntityState.Deleted:
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
using BuildingBlocks.Domain.Event;
|
||||||
|
using BuildingBlocks.Domain.Model;
|
||||||
|
|
||||||
|
namespace BuildingBlocks.EventStoreDB.Events
|
||||||
|
{
|
||||||
|
public abstract class AggregateEventSourcing<TId> : Entity, IAggregateEventSourcing<TId>
|
||||||
|
{
|
||||||
|
private readonly List<IDomainEvent> _domainEvents = new();
|
||||||
|
public IReadOnlyList<IDomainEvent> 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using BuildingBlocks.Domain.Event;
|
||||||
|
using BuildingBlocks.Domain.Model;
|
||||||
|
|
||||||
|
namespace BuildingBlocks.EventStoreDB.Events
|
||||||
|
{
|
||||||
|
public interface IAggregateEventSourcing : IProjection, IEntity
|
||||||
|
{
|
||||||
|
IReadOnlyList<IDomainEvent> DomainEvents { get; }
|
||||||
|
IEvent[] ClearDomainEvents();
|
||||||
|
long Version { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAggregateEventSourcing<out T> : IAggregateEventSourcing
|
||||||
|
{
|
||||||
|
T Id { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1,11 +1,10 @@
|
|||||||
using BuildingBlocks.Domain.Model;
|
using BuildingBlocks.EventStoreDB.Events;
|
||||||
using BuildingBlocks.EventStoreDB.Events;
|
|
||||||
using BuildingBlocks.EventStoreDB.Serialization;
|
using BuildingBlocks.EventStoreDB.Serialization;
|
||||||
using EventStore.Client;
|
using EventStore.Client;
|
||||||
|
|
||||||
namespace BuildingBlocks.EventStoreDB.Repository;
|
namespace BuildingBlocks.EventStoreDB.Repository;
|
||||||
|
|
||||||
public interface IEventStoreDBRepository<T> where T : class, IAggregate<long>
|
public interface IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<long>
|
||||||
{
|
{
|
||||||
Task<T?> Find(long id, CancellationToken cancellationToken);
|
Task<T?> Find(long id, CancellationToken cancellationToken);
|
||||||
Task<ulong> Add(T aggregate, CancellationToken cancellationToken);
|
Task<ulong> Add(T aggregate, CancellationToken cancellationToken);
|
||||||
@ -13,7 +12,7 @@ public interface IEventStoreDBRepository<T> where T : class, IAggregate<long>
|
|||||||
Task<ulong> Delete(T aggregate, long? expectedRevision = null, CancellationToken cancellationToken = default);
|
Task<ulong> Delete(T aggregate, long? expectedRevision = null, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EventStoreDBRepository<T>: IEventStoreDBRepository<T> where T : class, IAggregate<long>
|
public class EventStoreDBRepository<T>: IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<long>
|
||||||
{
|
{
|
||||||
private readonly EventStoreClient eventStore;
|
private readonly EventStoreClient eventStore;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using BuildingBlocks.Domain.Model;
|
using BuildingBlocks.Domain.Model;
|
||||||
|
using BuildingBlocks.EventStoreDB.Events;
|
||||||
using BuildingBlocks.Exception;
|
using BuildingBlocks.Exception;
|
||||||
|
|
||||||
namespace BuildingBlocks.EventStoreDB.Repository;
|
namespace BuildingBlocks.EventStoreDB.Repository;
|
||||||
@ -9,7 +10,7 @@ public static class RepositoryExtensions
|
|||||||
this IEventStoreDBRepository<T> repository,
|
this IEventStoreDBRepository<T> repository,
|
||||||
long id,
|
long id,
|
||||||
CancellationToken cancellationToken
|
CancellationToken cancellationToken
|
||||||
) where T : class, IAggregate<long>
|
) where T : class, IAggregateEventSourcing<long>
|
||||||
{
|
{
|
||||||
var entity = await repository.Find(id, cancellationToken);
|
var entity = await repository.Find(id, cancellationToken);
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ public static class RepositoryExtensions
|
|||||||
Action<T> action,
|
Action<T> action,
|
||||||
long? expectedVersion = null,
|
long? expectedVersion = null,
|
||||||
CancellationToken cancellationToken = default
|
CancellationToken cancellationToken = default
|
||||||
) where T : class, IAggregate<long>
|
) where T : class, IAggregateEventSourcing<long>
|
||||||
{
|
{
|
||||||
var entity = await repository.Get(id, cancellationToken);
|
var entity = await repository.Get(id, cancellationToken);
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
using Booking.Booking.Events.Domain;
|
using Booking.Booking.Events.Domain;
|
||||||
using Booking.Booking.Models.ValueObjects;
|
using Booking.Booking.Models.ValueObjects;
|
||||||
using BuildingBlocks.Domain.Model;
|
using BuildingBlocks.Domain.Model;
|
||||||
|
using BuildingBlocks.EventStoreDB.Events;
|
||||||
|
|
||||||
namespace Booking.Booking.Models;
|
namespace Booking.Booking.Models;
|
||||||
|
|
||||||
public class Booking : Aggregate<long>
|
public class Booking : AggregateEventSourcing<long>
|
||||||
{
|
{
|
||||||
public Booking()
|
public Booking()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user