Mac上Visual Studio中EF7 Code First迁移异常问题
问题描述
我近期更换为Mac M1设备,安装了Visual Studio与.NET 7,通过Docker容器运行SQL Server,正在开发ASP.NET Core 7 MVC Web应用。
删除SQL Server中的数据库与本地迁移文件夹后,通过NuGet包管理器控制台执行:
Add-Migration Initial -Context DB
迁移文件夹成功生成,包含Initial迁移类。但执行Update-Database命令后,仅创建了__EFMigrationsHistory表,其余业务表均未生成。
若再执行:
Add-Migration SecondMigration -Context DB
并执行更新命令,所有业务表会被创建,但会抛出部分表已存在的错误。
添加第三次迁移并更新数据库时,EF会尝试再次执行第一次迁移,查看__EFMigrationsHistory表可见migrationID仍为第一次迁移的ID,似乎每次执行update-database都会使用错误的迁移版本。
我想知道是否有相关配置可设置,或是需要在执行Update-Database命令时显式指定迁移版本?令我困惑的是,Initial迁移类中明明包含所有业务表的创建代码,为何仅生成了__EFMigrationsHistory表。
相关代码
DB上下文类
public class DB : DbContext { public DB(DbContextOptions<DB> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("dbo"); modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); modelBuilder.Entity<User>() .HasQueryFilter(a=>a.Id != 1); foreach (var foreignKey in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) { foreignKey.DeleteBehavior = DeleteBehavior.NoAction; } } public DbSet<ApiRequest> ApiRequest { get; set; } public DbSet<EmailLog> EmailLog { get; set; } public DbSet<NotificationDelivery> NotificationDelivery { get; set; } public DbSet<EmailTemplate> EmailTemplate { get; set; } public DbSet<ErrorLog> ErrorLog { get; set; } public DbSet<GeoLocation> GeoLocation { get; set; } }
实体类示例
[Table("ApiRequest")] public class ApiRequest { public long Id { get; set; } public string Name { get; set; } public DateTime LastUpdated { get; set; } public bool Active { get; set; } }
实体配置示例
public class ApiRequestConfig : IEntityTypeConfiguration<ApiRequest> { public void Configure(EntityTypeBuilder<ApiRequest> modelBuilder) { modelBuilder .HasKey(x => x.Id); modelBuilder .Property(x => x.Id) .ValueGeneratedOnAdd(); modelBuilder .Property(x => x.Name) .IsRequired() .HasMaxLength(50); modelBuilder .Property(x => x.LastUpdated) .IsRequired() .HasColumnType("datetime2(0)"); modelBuilder .Property(x => x.Active) .IsRequired() .HasDefaultValue(true); } }
Program.cs配置
builder.Services.AddDbContext<DB>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("ClientDatabase")); });
迁移类示例
public partial class Initial : Migration { /// <inheritdoc /> protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.EnsureSchema( name: "dbo"); migrationBuilder.CreateTable( name: "ApiRequest", schema: "dbo", columns: table => new { Id = table.Column<long>(type: "bigint", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), LastUpdated = table.Column<DateTime>(type: "datetime2(0)", nullable: false), Active = table.Column<bool>(type: "bit", nullable: false, defaultValue: true) }, constraints: table => { table.PrimaryKey("PK_ApiRequest", x => x.Id); }); } migrationBuilder.CreateTable( name: "EmailTemplate", schema: "dbo", columns: table => new { Id = table.Column<int>(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), Description = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), Template = table.Column<string>(type: "nvarchar(max)", nullable: false), Placeholders = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true), Active = table.Column<bool>(type: "bit", nullable: false, defaultValue: true) }, constraints: table => { table.PrimaryKey("PK_EmailTemplate", x => x.Id); }); }
解决思路与方案
1. 排查Initial迁移未执行的核心原因
Initial迁移类虽包含建表代码但未执行,大概率是迁移过程中出现了静默错误(EF未抛出异常),可通过以下方式排查:
- 执行更新命令时开启详细日志,查看执行细节:
Update-Database -Context DB -Verbose - 检查SQL Server容器的日志,确认是否有数据库层面的权限、Schema错误。
2. 彻底重置迁移与数据库
当前__EFMigrationsHistory表记录与实际数据库状态不匹配,按以下步骤重置:
- 删除SQL Server中的目标数据库,同时删除本地所有迁移文件夹。
- 重新生成干净的初始迁移:
Add-Migration Initial -Context DB -Force - 显式指定迁移版本执行更新:
Update-Database Initial -Context DB
3. 修复上下文配置的潜在问题
- 上下文的
OnModelCreating中引用了User实体,但未声明DbSet<User>,这可能导致查询过滤器抛出异常中断迁移,建议注释或补充DbSet<User>后重新测试。 - 确认
ApplyConfigurationsFromAssembly是否正确加载了所有实体配置类,避免因配置遗漏导致EF无法识别实体。
4. 规范后续迁移操作
- 每次重置迁移后,确保
__EFMigrationsHistory表与本地迁移文件完全同步。 - 若遇到版本匹配问题,执行
Update-Database时显式指定迁移名称(如Update-Database SecondMigration -Context DB)。 - 开发环境中避免手动修改迁移文件或数据库结构,保持EF迁移为唯一数据源。
内容的提问来源于stack exchange,提问作者Confused Guy
相关产品推荐
相关产品推荐

