cal5barton
cal5barton

Reputation: 1616

Domain event dispatching using Entity<TId> on DbContext.SaveChanges

I've implemented domain dispatching using a similar pattern here by overriding the SaveChanges method on my DbContext. I have entities with domain events that inherit a base abstract class that contains a list of domain events. I now want to enforce that the abstract class to have an Id property of a generic type.

Below is the base entity class before and after:

//BEFORE
public abstract class BaseEntity
{
    public List<BaseDomainEvent> Events = new List<BaseDomainEvent>();
}

//AFTER
public abstract class BaseEntity<TId>
{
    public virtual TId Id { get; protected set; }

    public List<BaseDomainEvent> Events = new List<BaseDomainEvent>();

    protected BaseEntity(TId id)
    {
        Id = id;
    }

    // EF requires an empty constructor
    protected BaseEntity()
    {
    }
}

On my DbContext.SaveChanges() I'm having a problem finding entities that have events now that I've changed the BaseEntity class. Below you will find the code before and after.

//BEFORE
public override int SaveChanges()
{
        int result = base.SaveChanges();

        // dispatch events only if save was successful
        var entitiesWithEvents = ChangeTracker.Entries<BaseEntity>()
            .Select(e => e.Entity)
            .Where(e => e.Events.Any())
            .ToArray();

        foreach (var entity in entitiesWithEvents)
        {
            var events = entity.Events.ToArray();
            entity.Events.Clear();
            foreach (var domainEvent in events)
            {
                _dispatcher.Dispatch(domainEvent);
            }
        }

        return result;
}

//AFTER
public override int SaveChanges()
{
        int result = base.SaveChanges();

        // dispatch events only if save was successful
        var entitiesWithEvents = ChangeTracker.Entries<BaseEntity<object>>()
            .Select(e => e.Entity)
            .Where(e => e.Events.Any())
            .ToArray();

        foreach (var entity in entitiesWithEvents)
        {
            var events = entity.Events.ToArray();
            entity.Events.Clear();
            foreach (var domainEvent in events)
            {
                _dispatcher.Dispatch(domainEvent);
            }
        }

        return result;
}

I can change ChangeTracker.Entries<BaseEntity<object>>() to ChangeTracker.Entries<BaseEntity<int>>() and it works for all entities with the Id of int but not for the ones that may contain a Guid or String as the Id type.

Any help would be appreciated!

Upvotes: 1

Views: 1556

Answers (1)

DavidG
DavidG

Reputation: 118947

One solution is to keep the original class and inherit from that:

public abstract class BaseEntity
{
    public List<BaseDomainEvent> Events = new List<BaseDomainEvent>();
}

public abstract class BaseEntity<TId> : BaseEntity
{
    public virtual TId Id { get; protected set; }

    protected BaseEntity(TId id)
    {
        Id = id;
    }

    // EF requires an empty constructor
    protected BaseEntity()
    {
    }
}

Now you don't need to change the SaveChanges method.

Upvotes: 2

Related Questions