【问题标题】:EF Core - dropping a column workaround (sqlite)EF Core - 删除列解决方法(sqlite)
【发布时间】:2017-06-13 15:53:43
【问题描述】:

is documented 并知道 EF 核心迁移脚本不支持删除列。所以我试着用手来做。

我的模型类是:

class Master
{
    public int Id { get; set; }
    public string ToBeDeleted { get; set; }
}

class Detail
{
    public int Id { get; set; }

    public Master Master { get; set; }
}

我的背景:

class Context : DbContext
{
    public DbSet<Master> Masters { get; set; }
    public DbSet<Detail> Details { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Filename=local.db");
        base.OnConfiguring(optionsBuilder);
    }
}

我创建了一个迁移脚本,然后运行以下程序来创建 db 文件并添加几行:

class Program
{
    static void Main(string[] args)
    {
        using (var context = new Context())
        {
            context.Database.Migrate();
            if(!context.Masters.Any())
            {
                var master = new Master {ToBeDeleted = "Some string"};
                context.Add(master);
                context.Add(new Detail {Master = master});
                context.SaveChanges();
            }
        }
    }
}

我删除了Master 类的ToBeDeleted 属性并生成了第二个迁移脚本,该脚本生成的非常简单的代码无法正常工作,因为它只会在未来得到支持:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.DropColumn(
        name: "ToBeDeleted",
        table: "Masters");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
   migrationBuilder.AddColumn<string>(
        name: "ToBeDeleted",
        table: "Masters",
        nullable: true);
}

所以是时候写我自己的东西了,这就是我尝试过的:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql("PRAGMA foreign_keys=OFF");
    migrationBuilder.CreateTable(
        name: "NEW_Masters",
        columns: table => new
        {
             Id = table.Column<int>(nullable: false)
                .Annotation("Sqlite:Autoincrement", true),
        },
         constraints: table =>
         {
             table.PrimaryKey("PK_Masters", x => x.Id);
         });
    migrationBuilder.Sql("INSERT INTO NEW_Masters SELECT Id FROM Masters;");
    migrationBuilder.DropTable("Masters");
    migrationBuilder.RenameTable("NEW_Masters", newName: "Masters");
    migrationBuilder.Sql("PRAGMA foreign_keys=OFF");
}

但是这会导致context.Database.Migrate() 抛出异常:

“Microsoft.Data.Sqlite.SqliteException”类型的未处理异常 发生在 Microsoft.EntityFrameworkCore.Relational.dll 中

附加信息:SQLite 错误 19:'FOREIGN KEY 约束 失败”。

最后一个问题:如何在迁移脚本中手动删除一列?

更新

根据我在讨论中得到的建议,我使用 Script-Migration 从迁移脚本生成 sql 并得到了这个:

CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
    "MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY,
    "ProductVersion" TEXT NOT NULL
);

CREATE TABLE "Masters" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Masters" PRIMARY KEY AUTOINCREMENT,
    "ToBeDeleted" TEXT
);

CREATE TABLE "Details" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Details" PRIMARY KEY AUTOINCREMENT,
    "MasterId" INTEGER,
    CONSTRAINT "FK_Details_Masters_MasterId" FOREIGN KEY ("MasterId") REFERENCES "Masters" ("Id") ON DELETE RESTRICT
);

CREATE INDEX "IX_Details_MasterId" ON "Details" ("MasterId");

INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20170127204056_Migration1', '1.1.0-rtm-22752');

INSERT INTO Masters (ToBeDeleted) VALUES ("ASDF"); --I've added this line manually for test only

INSERT INTO Details (MasterId) VALUES (1); --I've added this line manually for test only

PRAGMA foreign_keys="0";

CREATE TABLE "NEW_Masters" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Masters" PRIMARY KEY AUTOINCREMENT
);

INSERT INTO NEW_Masters SELECT Id FROM Masters;;

DROP TABLE "Masters";

ALTER TABLE "NEW_Masters" RENAME TO "Masters";

PRAGMA foreign_keys="1";

INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20170127204851_Migration2', '1.1.0-rtm-22752');

脚本运行良好。例外是 EF 在某处执行的一些外键检查。

【问题讨论】:

  • 哪一行抛出异常?
  • @CL.context.Database.Migrate()

标签: sql sqlite entity-framework-core


【解决方案1】:

EF core developers指出PRAGMA foreign_keys=0在SQLite的事务中不起作用,建议使用migrationBuilder.Sql方法来抑制事务的使用。

所以我想出了:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "NEW_Masters",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("Sqlite:Autoincrement", true),
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Masters", x => x.Id);
            });
        migrationBuilder.Sql("INSERT INTO NEW_Masters SELECT Id FROM Masters;");
        migrationBuilder.Sql("PRAGMA foreign_keys=\"0\"", true);
        migrationBuilder.Sql("DROP TABLE Masters", true);
        migrationBuilder.Sql("ALTER TABLE NEW_Masters RENAME TO Masters", true);
        migrationBuilder.Sql("PRAGMA foreign_keys=\"1\"", true);
    }

它成功了。

【讨论】:

  • 如果您可以删除数据库并删除现有迁移文件以重新开始:dotnet ef database drop -fdotnet ef migrations add InitialModeldotnet ef database update,请在 Startup 的 Configure 方法中为数据库播种并运行应用程序以播种数据库。这将避免使用 SQL Lite 的 ef 核心出现 DropForeignKeyOperation 错误
  • @JuniorM 如果您使用迁移来支持软件版本之间的数据库升级,这将不起作用...
【解决方案2】:

对于懒惰的人,我所做的是手动删除解决方案中的迁移,然后 sqlite db 添加了迁移。当出现无法删除的讨厌错误时,注释掉 up 方法的主体,如下所示:在生成的脚本中。然后更新数据库。当我将引用对象类型 SocialMediaLinks 添加到我的用户时,它生成了一个 fk 对我来说工作得很好。这不是适合所有人的解决方案,因为它可能会导致数据丢失。同时删除导致 fk 依赖的类实体。

//generated migration:

 protected override void Up(MigrationBuilder migrationBuilder)
        {
             //comment out--
            //migrationBuilder.DropColumn(
            //    name: "SocialMediaLinks",
            //    table: "ProfileUserVM");

            //migrationBuilder.DropColumn(
            //    name: "SocialMediaLinks",
            //    table: "AspUsers");
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.AddColumn<string>(
                name: "SocialMediaLinks",
                table: "ProfileUserVM",
                nullable: true);

            migrationBuilder.AddColumn<string>(
                name: "SocialMediaLinks",
                table: "AspUsers",
                nullable: true);
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    相关资源
    最近更新 更多