首页 > 解决方案 > ApplicationDbContext 认为 DomainEvent 是一个实体,但它不是

问题描述

使用上下文“ApplicationDbContext”。

System.InvalidOperationException:实体类型“DomainEvent”需要定义主键。如果您打算使用无密钥实体类型,请在“OnModelCreating”中调用“HasNoKey”。有关无密钥实体类型的详细信息,请参阅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);
}

标签: c#asp.net-core-5.0

解决方案


只需INotification用于您的域事件类型。

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

由于它现在是一个接口,它将被 EF Core 忽略。请参阅领域事件:设计和实现


推荐阅读