为什么 EF 无法将我的属性识别为主键?

问题描述 投票:0回答:1

我正在尝试使用 NUnit 在功能测试中的 Testcontainers MySQL 容器上进行数据库迁移,但 EF 无法将我的 Id 属性识别为主键。

public class MyClass : BaseAuditableEntity
{
    public required string SomeString { get; set; }

    public required AnotherClass AnotherClass { get; set; }

    public required byte[] C{ get; set; }

    public required byte[] D{ get; set; }
}

public abstract class BaseAuditableEntity : BaseEntity
{
    public DateTimeOffset Created { get; set; }

    public Guid? CreatedBy { get; set; }

    public DateTimeOffset LastModified { get; set; }

    public Guid? LastModifiedBy { get; set; }
}

public abstract class BaseEntity
{
    [Key]
    public Guid Id { get; set; }

    private readonly List<BaseEvent> _domainEvents = new();

    [NotMapped]
    public IReadOnlyCollection<BaseEvent> DomainEvents => _domainEvents.AsReadOnly();

    public void AddDomainEvent(BaseEvent domainEvent)
    {
        _domainEvents.Add(domainEvent);
    }

    public void RemoveDomainEvent(BaseEvent domainEvent)
    {
        _domainEvents.Remove(domainEvent);
    }

    public void ClearDomainEvents()
    {
        _domainEvents.Clear();
    }
}

public class MyClassCreatedEvent : BaseEvent
{
    public MyClass _myClass;

    public MyClass CreatedEvent(MyClass myClass)
    {
        _myClass= myClass;
    }
}

public abstract class BaseEvent : INotification
{
}

我还尝试使用其他数据类型,如 int 或 long,使用

[Key]
属性并将
Id
指定为模型构建器中的键。

简化示例:

[OneTimeSetUp]
public async Task RunBeforeAnyTests()
{
    _database = await TestDatabaseFactory.CreateAsync();
}

public static class TestDatabaseFactory
{
    public static async Task<ITestDatabase> CreateAsync()
    {
        var database = new TestcontainersTestDatabase();

        await database.InitialiseAsync();

        return database;
    }
}

public class TestcontainersTestDatabase : ITestDatabase
{
    private readonly MySqlContainer _container;
    private DbConnection _connection = null!;
    private string _connectionString = null!;
    private Respawner _respawner = null!;

    public TestcontainersTestDatabase()
    {
        _container = new MySqlBuilder()
            .WithAutoRemove(true)
            .Build();
    }

    public async Task InitialiseAsync()
    {
        await _container.StartAsync();

        _connectionString = _container.GetConnectionString();

        _connection = new MySqlConnection(_connectionString);

        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseMySql(_connectionString, ServerVersion.AutoDetect(_connectionString))
            .Options;

        var context = new ApplicationDbContext(options);

        context.Database.Migrate();

        _respawner = await Respawner.CreateAsync(_connectionString, new RespawnerOptions
        {
            TablesToIgnore = ["__EFMigrationsHistory"]
        });
    }

    public async Task DisposeAsync()
    {
        await _connection.DisposeAsync();
        await _container.DisposeAsync();
    }
}

public interface ITestDatabase
{
    Task InitialiseAsync();

    Task DisposeAsync();
}


 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
 {
     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
     {
     }

     public DbSet<MyClass> MyClass => Set<MyClass>();
     
     protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<MyClass>().HasKey(e => e.Id);
        
        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
        base.OnModelCreating(builder);
    }
}

public class ApplicationUser : IdentityUser
{
}

public interface IApplicationDbContext
{
    IQueryable<TEntity> Set<TEntity>() where TEntity : class;

    DbSet<MyClass> MyClass{ get; }

    Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}

尝试迁移总会回来

OneTimeSetUp:System.InvalidOperationException:实体类型 “MyClass”需要定义主键。如果您打算 使用无键实体类型,在“OnModelCreating”中调用“HasNoKey”。

这是一个使用 EF Core 8 和 Pomelo EF Core MySQL 的 .NET 8 项目

有人对此有想法吗?根据我的经验,EF 会自动将 Id 属性识别为主键。

提前致谢

c# entity-framework .net-8.0
1个回答
0
投票

您必须像 DbContext 类中那样配置主键

 protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //Configure Primary Key using HasKey method
            modelBuilder.Entity<Student>().HasKey(s => s.StudentRegdNumber);
        }

© www.soinside.com 2019 - 2024. All rights reserved.