Reputation: 6311
Using context 'ApplicationDbContext'.
System.InvalidOperationException: The entity type 'DomainEvent' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
ApplicationDbContext thinks that DomainEvent is an entity, but it is not. It fails my migrations. What does make it look like so?
public abstract class Entity
{
public int Id { get; set; }
public ICollection<DomainEvent> DomainEvents { get; } = new Collection<DomainEvent>();
public void AddDomainEvent(DomainEvent eventItem)
{
DomainEvents.Add(eventItem);
}
public void RemoveDomainEvent(DomainEvent eventItem)
{
DomainEvents.Remove(eventItem);
}
}
public class Bot : Entity, IAggregateRoot
{
public string Symbol { get; set; }
}
public interface IAggregateRoot
{
}
public abstract class DomainEvent : INotification
{
public DateTime DateOccurred { get; protected set; } = DateTime.UtcNow;
}
public class BotCompletedEvent : DomainEvent
{
public BotCompletedEvent(Bot completedItem)
{
CompletedItem = completedItem;
}
public Bot CompletedItem { get; set; }
}
public class ApplicationDbContext : DbContext, IUnitOfWork
{
private readonly IMediator _mediator;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IMediator mediator)
: base(options)
{
_mediator = mediator;
}
public DbSet<Bot> Bots { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
base.OnModelCreating(modelBuilder);
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new())
{
var entitiesWithEvents = ChangeTracker.Entries<Entity>()
.Select(e => e.Entity)
.Where(e => e.DomainEvents.Any())
.ToList();
foreach (var entity in entitiesWithEvents)
{
var events = entity.DomainEvents;
entity.DomainEvents.Clear();
foreach (var domainEvent in events)
{
await _mediator.Publish(domainEvent, cancellationToken).ConfigureAwait(false);
}
}
return await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
public override int SaveChanges()
{
return SaveChangesAsync().GetAwaiter().GetResult();
}
}
public interface IUnitOfWork
{
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
Upvotes: 0
Views: 302
Reputation: 5141
Simply use INotification
for your domain events type.
public ICollection<INotification> DomainEvents { get; } = new Collection<INotification>();
Since it is now an interface, it will be ignored by EF Core. See Domain events: design and implementation.
Upvotes: 2