我正在尝试使用 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 属性识别为主键。
提前致谢
您必须像 DbContext 类中那样配置主键
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Configure Primary Key using HasKey method
modelBuilder.Entity<Student>().HasKey(s => s.StudentRegdNumber);
}