2016-03-21 4 views
2

Ich möchte eine neue Spalte mit einem eindeutigen Index zu einer vorhandenen Tabelle hinzufügen, wobei eine Code-Erstmigration verwendet wird. Da die Tabelle bereits Daten enthält, werden alle vorhandenen Zeilen für die neue Spalte beim Erstellen auf NULL gesetzt. Die Migration kann nicht angewendet werden, da dies die eindeutige Einschränkung des neuen Index verletzt.Behandeln von Duplikaten beim Hinzufügen eines eindeutigen Index zur Tabelle mit vorhandenen Zeilen im Code. Erste Migration

Hier ist meine Migration:

public override void Up() 
{ 
    AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 32)); 
    // How can I update existing rows here? 
    CreateIndex("dbo.SignInToken", "Token", unique: true); 
} 

Und der Fehler:

The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.SignInToken' and the index name 'IX_Token'. The duplicate key value is().

Die neue Spalte eine zufällig generierte Zeichenfolge enthält, die ich im Code festgelegt.

Ich weiß, dass ich die Sql Methode verwenden kann, um Raw SQL innerhalb der Migration auszuführen. Ich dachte daran, einen Cursor zu verwenden, um jede Zeile zu aktualisieren, aber dann müsste ich eine gespeicherte Prozedur schreiben, um die C# -Methode nachzuahmen, die das zufällige Token generiert. Ich würde es vorziehen, dies nicht tun zu müssen. Eine andere Sache, an die ich dachte, war, dass, wenn es eine Möglichkeit gäbe, alle Zeilen abzurufen, ich sie durchlaufen und die Update-Anweisungen für jede Zeile mit der Methode Sql ausführen könnte, aber ich weiß nicht, ob das möglich ist.

Gibt es eine Möglichkeit, alle vorhandenen Zeilen einzeln innerhalb der Migration zu aktualisieren, bevor die eindeutige Einschränkung hinzugefügt wird?

Antwort

3

Eine Lösung besteht darin, den Primärschlüssel in die neue Spalte zu kopieren. Dies kann dann bei Bedarf in der Seed-Methode aktualisiert werden.

Aktualisiert Migration:

public override void Up() 
{ 
    AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 40)); 
    Sql("UPDATE dbo.SignInToken SET Token = Id"); 
    CreateIndex("dbo.SignInToken", "Token", unique: true); 
} 

Dann können Sie die DbContext aus der Seed Methode verwenden, um die Zeilen bei Bedarf zu aktualisieren. Eine gewisse Logik wäre erforderlich, um sicherzustellen, dass neue Daten bei zukünftigen Migrationen nicht überschrieben werden (z. B. nur die Zeile aktualisieren, wenn Id == Token).

+0

Diese Lösung hat gut für mich funktioniert. Ich musste mich eigentlich nicht darum kümmern, die Daten in meiner Seed-Methode zu aktualisieren, sondern diese Informationen für andere zu übernehmen. – Sam

0

Auch im Fall, dass Sie nicht eine bereits bestehende eindeutige Spalte (zum Kopieren es Werte) Sie haben haben und wollen eine einzigartige Spalte einer Tabelle hinzufügen, die einige Zeilen haben schon können Sie versuchen, diesen Ansatz

AddColumn("dbo.SignInToken", 
      "Token", 
      c => c.Int(nullable: false, 
        defaultValueSql: "CONVERT(int, CONVERT(VARBINARY(16), NEWID(), 1))")); 

CreateIndex("dbo.IriSqlServerLayer", "Order", unique: true, name: "IX_UniqueOrder"); 
Verwandte Themen