ApplicationDbContext 认为 DomainEvent 是一个实体,但它不是

ApplicationDbContext thinks that DomainEvent is an entity but it is not

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 认为DomainEvent 是一个实体,其实不是。它使我的迁移失败。是什么让它看起来像这样?

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);
}

只需使用 INotification 作为您的域事件类型。

public ICollection<INotification> DomainEvents { get; } = new Collection<INotification>();

因为它现在是一个接口,所以它会被 EF Core 忽略。参见 Domain events: design and implementation