Ho implementato il seguente schema per jbogard:Come gestire gli eventi di dominio generati dai gestori di eventi?
http://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/
Immaginate la seguente entità Coupon
ed evento CouponActivatedEvent
:
public class Coupon : DomainEntity
{
public virtual User User { get; private set; }
// ...omitted...
public void Activate(User user)
{
if (User != null)
throw new InvalidOperationException("Coupon already activated");
User = user;
Events.Add(new CouponActivatedEvent(this));
}
}
Il seguente gestore di eventi CouponActivatedHandler
:
public class CouponActivatedHandler : IDomainEventHandler<CouponActivatedEvent>
{
public void Handle(CouponActivatedEvent e)
{
// user gets 5 credits because coupon was activated
for (int i = 0; i < 5; i++)
{
e.Coupon.User.AddCredit(); // raises UserReceivedCreditEvent and CreditCreatedEvent
}
}
}
Il seguente SaveChanges
override sul DbContext
(Entity Framework 6), tratta dal post del blog di jbogard:
public override int SaveChanges()
{
var domainEventEntities = ChangeTracker.Entries<IDomainEntity>()
.Select(po => po.Entity)
.Where(po => po.Events.Any())
.ToArray();
foreach (var entity in domainEventEntities)
{
var events = entity.Events.ToArray();
entity.Events.Clear();
foreach (var domainEvent in events)
{
_dispatcher.Dispatch(domainEvent);
}
}
return base.SaveChanges();
}
Se ora attiviamo un coupon, questo aumenterà il CouponActivatedEvent
. Quando si chiama SaveChanges
, verrà eseguito il gestore, e UserReceivedCreditEvent
e verrà sollevata CreditCreatedEvent
. Non saranno gestiti comunque. Sto fraintendendo il modello? Oppure l'override SaveChanges
non è appropriato?
Ho preso in considerazione la creazione di un ciclo che verrà ripetuto fino a quando non vengono sollevati nuovi eventi prima di passare a base.SaveChanges();
... ma sono preoccupato che creerò casualmente cicli infiniti. In questo modo:
public override int SaveChanges()
{
do
{
var domainEventEntities = ChangeTracker.Entries<IDomainEntity>()
.Select(po => po.Entity)
.Where(po => po.Events.Any())
.ToArray();
foreach (var entity in domainEventEntities)
{
var events = entity.Events.ToArray();
entity.Events.Clear();
foreach (var domainEvent in events)
{
_dispatcher.Dispatch(domainEvent);
}
}
}
while (ChangeTracker.Entries<IDomainEntity>().Any(po => po.Entity.Events.Any()));
return base.SaveChanges();
}
Grazie, hai chiarito più cose per me. Sei a conoscenza di un progetto di esempio disegnato nel modo in cui descrivi? Penso di avere l'idea, non sono sicuro di come implementarlo correttamente. – Korijn
Esempio, non proprio. Ma comincia a farlo, la pratica rende perfetti. Fai attenzione a ciò che ti sembra ingombrante, prova a fare il refattore, ecc. Il DDD è appreso eseguendolo. – MikeSW
Ora capisco, in particolare che * i gestori di eventi reagiscono a cose che si sono verificate in passato * ha spiegato molto. – Korijn