18

Ich habe eine Tabelle, die zusätzliche Daten für einige Zeilen einer Tabelle wie speichert:Entity Framework-Code erster Migrations: Set Primärschlüsselwert

public class QuoteExtra 
{ 
    [Key] 
    public int QuoteId { get; set; } 
    // More fields here 
} 

Ich mag würde zu können, fügen Sie Zeilen dieser Tabelle wo ich den PK explizit setze.

Wenn ich es einfach wie oben belassen habe, wird durch Setzen eines Werts und Übergeben der Zeile der Wert verworfen und durch den automatisch generierten Wert aus der Datenbank ersetzt (und die Spalte wird im aktuellen Schema als Identitätsspalte definiert)).

Dies scheint die richtige Lösung zu sein:

public class QuoteExtra 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public int QuoteId { get; set; } 
    // More fields here 
} 

dies jedoch stattdessen wird mir die Ausnahme:

Kann nicht expliziten Wert für Identitätsspalte in der Tabelle ‚EnumTest‘ einfügen, wenn IDENTITY_INSERT eingestellt wird AUS.

Also, wie schreibe ich meine Klasse, so dass ich den Wert eines Primärschlüssels in EF festlegen kann?

Edit:

ich das Hinzufügen versuchte die folgende Code-basierte Migration IDENTITY_INSERT auf ON zu setzen:

public override void Up() 
{ 
    Sql("SET IDENTITY_INSERT QuoteExtra ON"); 
} 

ich es lief und versuchte es noch einmal, aber bekam die gleiche Ausnahme wie oben. Was seltsam ist, ist, dass die Datenbank diese Einstellung widerspiegelt, und das direkte Ausführen von SQL erlaubt mir, willkürliche Werte für den Primärschlüssel einzufügen - so scheint es, dass Entity Framework selbst diese Regel durchsetzt und nicht erkennt, dass IDENTITY_INSERT nicht drin ist Tatsache ausgeschaltet. Muss ich es irgendwo in EF selbst einstellen?

Edit 2:

I IDENTITY_INSERT falsch verstanden; Ich nahm an, es einmal für diesen Tisch auf unbestimmte Zeit zu setzen. In der Tat lebt es so lange wie die "Session", was bedeutet, dass zum Beispiel das Setzen in einer Migration bedeutet, dass es lebt ... solange diese Migration läuft und keine Auswirkungen auf zukünftige Verbindungen wie meine spätere .Add() mit EF hat Das erklärt, warum ich immer noch diese Ausnahme habe - die DB ist wirklich die Quelle der Ausnahme, nicht EF. Da IDENTITY_INSERT auf höchstens eine Tabelle pro Sitzung beschränkt ist, ist dies eine ziemlich ineffiziente Art und Weise - das Erstellen einer Identity PK-Spalte an erster Stelle scheint eine bessere Route zu sein.

+0

Was meinst du mit * Was seltsam ist die Datenbank diese Einstellung widerspiegelt *? –

+0

Was ich meinte war, dass ich Werte einfügen konnte, wenn ich nach dem Ausführen des identity_insert on-Befehls Raw-SQL verwendete - aber jetzt sehe ich, warum -, weil die Einstellung für die Dauer einer Sitzung und in Raw-SQL aktiviert ist In Sql Server Management Studio blieb ich innerhalb einer Sitzung, während meine EF Migration und der folgende Testcode getrennte Sitzungen waren. –

+0

Ja. Die Identity-Einfügung bezieht sich auf die Verbindung. Wenn Sie sicherstellen, dass der Code in derselben Verbindung ausgeführt wird, sollten Sie ihn verwenden können. Aber es ist irgendwie schwarze Magie, besonders wenn man über Migrationen nachdenkt. –

Antwort

32

Dies ist der richtige Weg, um eine PK ohne Identität Autoincrement schaffen aktiviert:

public class QuoteExtra 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public int QuoteId { get; set; } 
    // More fields here 
} 

Wenn Sie jedoch DatabaseGenerated (DatabaseGeneratedOption.None) hinzufügen] nach EF Migrationen hat bereits die Tabelle erstellt, tut es ruhig nichts an den Tisch.Wenn dies Ihr Szenario müssen Sie eine manuelle Migration hinzuzufügen, um die Tabelle löschen:

add-migration RecreateQuoteExtra 

Und in der Migration:

public override void Up() 
{ 
    DropTable("QuoteExtra"); 
} 

EF automatische Migrationen werden dann automatisch die Tabelle ohne Identitäts Constraint neu erstellen, Damit können Sie den PK-Wert jederzeit einstellen, ohne spezielle Befehle wie IDENTITY_INSERT ON ausführen zu müssen.

Es klingt wie eine weniger destruktive Möglichkeit, dies in EF7 ("Data Motion") kommt, oder Sie könnten eine Menge manuell sql selbst in der Migration schreiben, um temporäre Tabellen zu erstellen und Daten zu verschieben, wenn Sie wollten Vermeiden Sie den Verlust vorhandener Daten in der Tabelle.

BEARBEITEN: Je nach Szenario erstellt EF Migrations die Tabelle möglicherweise nicht neu. Wenn die Klasse bereits existiert und bereits zu Ihrem DbContext hinzugefügt wurde, wird sie einfach fallengelassen, dh Ihre manuelle Migration muss nicht nur abgebrochen werden aber auch die Tabelle erstellen. Keine große Sache, da der Gerüstcode, den EF Migrations für Sie aus der Add-Migration generiert, diese Anweisungen für Sie erstellt, aber es ist ein bisschen mehr Code, den Sie bei Problemen überprüfen können.

+0

Das hat gut für mich funktioniert. Vielen Dank. – BrainSlugs83

4

Es ist die richtige Lösung, aber nur für eine neue Tabelle. Wenn Sie die datenbankgenerierte Option für eine vorhandene Tabelle ändern, können EF-Migrationen diese Änderung nicht durchführen und Ihre QuoteId-Spalte ist weiterhin als Identity in der Datenbank markiert.

+0

Die Docs auf IDENTITY_INSERT geben keine solche Einschränkung an, und tatsächlich kann ich diese in Raw SQL lange nach der Erstellung der Tabelle aktivieren und deaktivieren und Werte für den PK angeben. http://msdn.microsoft.com/en-us/library/ms188059.aspx Sie sagen dort höchstens eine Tabelle kann dies pro Sitzung aktiviert haben, was bedeutet, dass ich dies nicht über eine Migration, sondern direkt vor einem aktivieren muss INSERT und dann wieder ausschalten, was ziemlich hässlich ist. Es scheint, als wäre es besser, einen Weg zu finden, die Identity-Funktionalität auszuschalten. –

+0

EF bietet keine direkte Möglichkeit, mit der IDENTITY_INSERT-Einstellung zu spielen. Meine ursprüngliche Antwort zielte auf dein Spielen mit 'DatabaseGeneratedOption' ab. –

+0

Ich sehe, was Sie jetzt sagen wollten. EF Migrations muss die Tabelle tatsächlich löschen, um diese Änderung durchzuführen - dies kann eine Einschränkung von SQL Server sein. –

1

Ich konnte dieses Problem mit Ihren Hints nicht lösen, dann habe ich versucht, die gesamte Datenbank neu zu erstellen, aber es hat auch nicht funktioniert.

Um dies zu beheben, müssen Sie die identity: true Eigenschaft bei der ersten (!) Erstellung der Spalte (z. B. Initial-Migration) entfernen.

Vielleicht wird es jemand helfen ..

+0

Ja, das ist was meine Antwort sagt. –

+0

Das Szenario ist ein wenig komplizierter, als ich dachte. Wenn automatische Migrationen aktiviert sind, genügt ein (wahrscheinlich geändertes) Modell mit DatabaseGeneratedOption.None in der Primärschlüsselspalte SET IDENTITY INSERT ON für die Tabelle in einer Transaktion. Wenn jedoch eine manuelle Migration mithilfe des ersten Ansatzes für Code generiert wird, weist die Migration die Attribute identity: true für die Primärschlüsselspalten auf. Diese Einstellung wird nicht durch die automatische Migration festgelegt, daher sollte sie vor dem Erstellen der Datenbank aus der Up-Methode() entfernt werden. –

Verwandte Themen