EFコア - 列の回避策を削除する(sqlite)

entity-framework-core sql sqlite3

質問

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プロパティを削除して、それが将来サポートされるだけなので動作しない非常に簡単なコードを生成する2番目の移行スクリプトを生成しました:

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によってどこかで実行されるいくつかの外部キーチェックです。

受け入れられた回答

EFのコア開発者は、 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);
    }

それはトリックです。


人気のある回答

lazierのために、私は手動でソリューションの移行を削除し、sqlite dbはマイグレーションを追加しました。その厄介なエラーが出てきたら、ドロップすることはできません。そのようにアップメソッドの本文をコメントアウトします:生成されたスクリプトで.dbを更新します。参照オブジェクトタイプSocialMediaLinksをユーザに追加したときにfkを生成したときにうまくいきました。これは、データ損失を引き起こす可能性があるため、すべてに適した解決策ではありません.ALKは、fkの依存を引き起こしていたCLASS ENTITYを削除します。

//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);
        }


Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ