You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 6执行add-migration时重复创建已存在数据表问题

问题现象

先前迁移中已经通过migrationBuilder.CreateTable完成了AppDespesaExtraOrcamentaria表的创建,仅调整实体的唯一索引配置后执行add-migration命令,新生成的迁移文件没有按预期输出索引增量变更语句,反而重复生成了该表的完整建表逻辑。

先前迁移中的建表代码

migrationBuilder.CreateTable(
            name: "AppDespesaExtraOrcamentaria",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Exercicio = table.Column<int>(type: "int", nullable: false),
                CodigoReduzido = table.Column<int>(type: "int", nullable: false),
                Conta = table.Column<long>(type: "bigint", nullable: false),
                Complemento = table.Column<short>(type: "smallint", nullable: false),
                Descricao = table.Column<string>(type: "varchar(50)", nullable: true),
                FundoId = table.Column<int>(type: "int", nullable: false),
                FornecedorId = table.Column<int>(type: "int", nullable: false),
                FonteDeRecursoId = table.Column<int>(type: "int", nullable: true),
                CodigoDeAplicacaoId = table.Column<int>(type: "int", nullable: true),
                DestinacaoRecursoId = table.Column<int>(type: "int", nullable: true),
                FonteDeRecursoSICONFIId = table.Column<int>(type: "int", nullable: true),
                ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
                CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
                CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
                LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_AppDespesaExtraOrcamentaria", x => x.Id);
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppCodigoDeAplicacao_CodigoDeAplicacaoId",
                    column: x => x.CodigoDeAplicacaoId,
                    principalTable: "AppCodigoDeAplicacao",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppDestinacaoRecurso_DestinacaoRecursoId",
                    column: x => x.DestinacaoRecursoId,
                    principalTable: "AppDestinacaoRecurso",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFonteDeRecurso_FonteDeRecursoId",
                    column: x => x.FonteDeRecursoId,
                    principalTable: "AppFonteDeRecurso",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFonteDeRecursoSICONFI_FonteDeRecursoSICONFIId",
                    column: x => x.FonteDeRecursoSICONFIId,
                    principalTable: "AppFonteDeRecursoSICONFI",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFornecedor_FornecedorId",
                    column: x => x.FornecedorId,
                    principalTable: "AppFornecedor",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFundo_FundoId",
                    column: x => x.FundoId,
                    principalTable: "AppFundo",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
            });
migrationBuilder.CreateIndex(
            name: "IX_AppDespesaExtraOrcamentaria_TenantId_Conta",
            table: "AppDespesaExtraOrcamentaria",
            columns: new[] { "TenantId", "Conta" },
            unique: true,
            filter: "[TenantId] IS NOT NULL");

异常生成的新迁移代码

migrationBuilder.CreateTable(
            name: "AppDespesaExtraOrcamentaria",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Exercicio = table.Column<int>(type: "int", nullable: false),
                CodigoReduzido = table.Column<int>(type: "int", nullable: false),
                Conta = table.Column<long>(type: "bigint", nullable: false),
                Complemento = table.Column<short>(type: "smallint", nullable: false),
                Descricao = table.Column<string>(type: "varchar(50)", nullable: true),
                FundoId = table.Column<int>(type: "int", nullable: false),
                FornecedorId = table.Column<int>(type: "int", nullable: false),
                FonteDeRecursoId = table.Column<int>(type: "int", nullable: true),
                CodigoDeAplicacaoId = table.Column<int>(type: "int", nullable: true),
                DestinacaoRecursoId = table.Column<int>(type: "int", nullable: true),
                FonteDeRecursoSICONFIId = table.Column<int>(type: "int", nullable: true),
                ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
                CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
                CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
                LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_AppDespesaExtraOrcamentaria", x => x.Id);
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppCodigoDeAplicacao_CodigoDeAplicacaoId",
                    column: x => x.CodigoDeAplicacaoId,
                    principalTable: "AppCodigoDeAplicacao",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppDestinacaoRecurso_DestinacaoRecursoId",
                    column: x => x.DestinacaoRecursoId,
                    principalTable: "AppDestinacaoRecurso",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFonteDeRecurso_FonteDeRecursoId",
                    column: x => x.FonteDeRecursoId,
                    principalTable: "AppFonteDeRecurso",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFonteDeRecursoSICONFI_FonteDeRecursoSICONFIId",
                    column: x => x.FonteDeRecursoSICONFIId,
                    principalTable: "AppFonteDeRecursoSICONFI",
                    principalColumn: "Id");
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFornecedor_FornecedorId",
                    column: x => x.FornecedorId,
                    principalTable: "AppFornecedor",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
                table.ForeignKey(
                    name: "FK_AppDespesaExtraOrcamentaria_AppFundo_FundoId",
                    column: x => x.FundoId,
                    principalTable: "AppFundo",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
            });
migrationBuilder.CreateIndex(
            name: "IX_AppDespesaExtraOrcamentaria_TenantId_Conta_Complemento_Exercicio",
            table: "AppDespesaExtraOrcamentaria",
            columns: new[] { "TenantId", "Conta", "Complemento", "Exercicio" },
            unique: true,
            filter: "[TenantId] IS NOT NULL");

migrationBuilder.CreateIndex(
            name: "IX_AppDespesaExtraOrcamentaria_TenantId_Exercicio_CodigoReduzido",
            table: "AppDespesaExtraOrcamentaria",
            columns: new[] { "TenantId", "Exercicio", "CodigoReduzido" },
            unique: true,
            filter: "[TenantId] IS NOT NULL");

本次操作仅修改了表的唯一索引配置,预期生成删除旧索引、创建新索引的增量语句,实际却输出了完整建表逻辑。

问题原因

核心原因是EF Core的迁移快照与实际已应用的迁移状态不一致,EF Core判定该表尚未创建,因此生成了完整建表语句,常见触发场景有三类:

  • 手动修改过历史迁移文件的建表/建索引代码,没有同步更新对应迁移的Model快照
  • 多分支合并时迁移文件冲突未正确解决,导致快照丢失了该表的已创建记录
  • 实体对应的表名映射配置被意外修改,EF Core判定当前模型中的实体对应了一张全新的未创建表
解决方法

按以下步骤操作即可彻底修复:

  1. 先删除这次异常生成的迁移文件,同时删除对应文件名末尾带.Designer.cs的快照附属文件
  2. 检查DbContext中该实体的表名映射配置,确认ToTable("AppDespesaExtraOrcamentaria")配置没有改动,和历史迁移中的表名完全一致
  3. 打开Migrations目录下的*[你的DbContext名称]ModelSnapshot.cs*文件,搜索AppDespesaExtraOrcamentaria,确认快照中是否存在该表的完整定义:
    • 如果不存在,找到最近一次创建该表的迁移文件,将其中的表结构定义、外键、索引定义同步复制到Model快照中,和其他已存在表的格式保持一致
    • 如果存在,检查表名、列名、主键配置是否和历史迁移中的定义完全匹配,修正不一致的配置
  4. 重新执行add-migration命令,此时生成的迁移文件就只会包含索引调整的增量逻辑:删除旧的IX_AppDespesaExtraOrcamentaria_TenantId_Conta索引,创建两个新的唯一索引,不会再出现重复建表的代码。

注意:不要直接手动修改新生成的迁移文件、删掉CreateTable部分就直接使用,这种方式没有修复底层快照不一致的问题,后续生成迁移还是会出现同类异常。

内容的提问来源于stack exchange,提问作者Heitor Giacomini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 02:46:00