Wenn wir eine Property oder einen Foreign Key mit einer Migration zur SQlite Datenbank mittels EF Core hinzufügen wollen, schlägt dies mit der folgenden Meldung fehl:

SQlite Migration anwenden schlägt fehl (hier DropColumn)

Das Problem ist hier, dass der Sqlite Provider für Ef-core (Microsoft.EntityFrameworkCore.Sqlite) nur die folgenden Alter Table statements unterstützt (die anderen werden von Sqlite selbst nicht unterstützt).

  • Rename table
  • Rename Column
  • Add Column

Alle anderen sind nicht unterstützt und deshalb in ef-core nicht verfügbar!

Lösung!

Dennoch sind wir nicht verloren!

Wir gehen bis auf das update database command genauso vor wie immer wenn wir eine Migration erstellen.

Aber anstelle vom database update, öffnen wir in diesem Fall die Migration.cs Datei, die den Namen unserer Migration trägt. (die mit den Up und Down Methoden).

Und darin gehen wir wie folgt vor:

  1. Den Code kommentieren/löschen, der ein nicht unterstütztes Command ausführt.
  2. Eine Temporäre Tabelle erstellen, in die wir die Daten der zu ändernden Tabelle kopieren
    Diese enthält die zusätzlichen Constraints, Columns usw.
  3. Foreign keys deaktivieren
  4. Alte Tabelle löschen
  5. Temporäre Tabelle umbenennen
  6. foreign keys reaktivieren
  7. Database update ausführen.

Für das obere Beispiel wäre das die Down Methode auf dem Revert einer Migration:
(siehe dazu das zugehörige Github Repo hier)

Drop Column (nicht funktional)

Wir ändern das wie folgt:

protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Temp_Products",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Start = table.Column<DateTime>(nullable: false, defaultValueSql: "datetime('now')"),
End = table.Column<DateTime>(nullable: false),
RoundId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.Id);
table.ForeignKey(
name: "FK_Products_Rounds_RoundId",
column: x => x.RoundId,
principalTable: "Rounds",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.Sql("INSERT INTO Temp_Products SELECT Id, Start, End, RoundId FROM Products;", true);
migrationBuilder.Sql("PRAGMA foreign_keys=\"0\"", true);
migrationBuilder.Sql("DROP TABLE Products;", true);
migrationBuilder.Sql("ALTER TABLE Temp_Products RENAME TO Products", true);
migrationBuilder.Sql("PRAGMA foreign_keys=\"1\"", true);
}
Fixed migration

Das sind die Schritte, die notwendig sind um unsere Migration für den Sqlite Provider von EF core korrekt durchzuführen.
Insgesamt ist dies immer erforderlich wenn wir eine der folgenden Änderungen an den POCOS /DbContext vornehmen wollen:

  • DatenTyp ändern
  • Foreign Key / Primary Key constraint hinzufügen
  • Property / Spalte entfernen
  • Allgemein constraints ändern

Für mehr zum Thema Entity Framework Core schaue in die Übersicht oder sieh dir meinen Online Kurs zu dem Thema an.

Categories: ef-core-de

1 Comment

marcusdotnet · 02/14/2022 at 16:03

Hallo Timo,

danke für den tollen Blockpost. Ich habe die letzten Tage viel Zeit mit den CASCADE Constraints und PRAGMA settings verschwendet. Was gefehlt hatte war letztendlich das Flag hinterm PRAGMA um die Transaktion zu ignorieren. Besten Dank für das Codebeispiel. Danke! 🙂

Gruß,
Marcus

Leave a Reply

Avatar placeholder