18

Mam tabelę, która przechowuje jakieś dodatkowe dane dla niektórych wierszach tabeli, takich jak:Entity Framework Code First Migracje: Set Primary Key Value

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

Chciałbym, aby móc dodać wiersze do tabeli gdzie wyraźnie ustawiłem PK.

Jeśli po prostu pozostawię to tak jak powyżej, ustawienie wartości i przesłanie wiersza powoduje, że wartość zostanie odrzucona i zastąpiona wartością wygenerowaną automatycznie z bazy danych (a kolumna jest zdefiniowana jako kolumna Tożsamość w rzeczywistym schemacie).

To wydaje się być dobrym rozwiązaniem:

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

Jednak zamiast tego dostaje mi wyjątek:

Nie można wstawić wyraźną wartość dla kolumny tożsamości w tabeli „EnumTest” kiedy IDENTITY_INSERT jest ustawiony na POZA.

Jak więc napisać moją klasę, aby móc ustawić wartość klucza podstawowego w EF?

Edit:

Próbowałem dodanie następującego migracji kodu opartego ustawić IDENTITY_INSERT ON:

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

Pobiegłem go i spróbował jeszcze raz, ale mam ten sam wyjątek jak wyżej. Dziwne jest to, że baza danych odzwierciedla to ustawienie, a bezpośrednie działanie SQL przeciwko niemu pozwala mi wstawiać dowolne wartości dla klucza podstawowego - więc wyglądałoby na to, że Entity Framework sam egzekwuje tę regułę i zaniedbuje rozpoznanie, że IDENTITY_INSERT nie jest fakt ustawiony na off. Czy muszę ustawić go gdzieś w samym EF?

Edit 2:

ja źle IDENTITY_INSERT; Zakładałem, że ustawiam go po raz pierwszy na tym stole na czas nieokreślony. W rzeczywistości żyje tak długo, jak "Sesja", co oznacza, że ​​na przykład ustawienie Migracji oznacza, że ​​ona żyje ... tak długo jak ta migracja działa i nie ma wpływu na przyszłe połączenia, takie jak moja później .Add() z EF , co wyjaśnia, dlaczego wciąż mam ten wyjątek - DB jest naprawdę źródłem wyjątku, a nie EF. Ponieważ IDENTITY_INSERT jest ograniczona do co najwyżej jednej tabeli na sesję, jest to dość nieefektywny sposób - nie tworzenie kolumny Identity PK na pierwszym miejscu wydaje się lepszą trasą.

+0

Co masz na myśli przez * Co dziwne jest baza danych nie odzwierciedla tego ustawienia? * –

+0

Co miałem na myśli to, że byłem w stanie wstawić wartości, jeśli użyłem surowego SQL, aby to zrobić po uruchomieniu polecenia identity_insert na - ale teraz widzę dlaczego - to dlatego, że ustawienie jest włączone dla długości sesji i w surowym SQL w Sql Server Management Studio pozostałam w zasięgu sesji, podczas gdy moja migracja EF i następujący po niej kod testowy są osobnymi sesjami. –

+0

Tak. Wkład identyfikacyjny jest powiązany z połączeniem. Jeśli upewnisz się, że twój kod działa w ramach tego samego połączenia, powinieneś móc z niego korzystać. Ale jest to jakaś czarna magia, szczególnie biorąc pod uwagę migracje. –

Odpowiedz

32

To jest właściwy sposób tworzenia PK bez Identity autoIncrement włączona:

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

Jeśli jednak dodać DatabaseGenerated (DatabaseGeneratedOption.None)] po EF Migracje stworzył już do stołu, to spokojnie nic nie robi na stół.Jeśli jest to Twój scenariusz trzeba dodać ręczną migrację upuścić tabeli:

add-migration RecreateQuoteExtra 

A w migracji:

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

EF automatyczna migracja będzie wtedy automatycznie odtworzyć tabelę bez ograniczeń Identity, co pozwoli ci ustawić wartość PK w dowolnym momencie, bez konieczności uruchamiania żadnych specjalnych poleceń, takich jak IDENTITY_INSERT ON.

Wygląda na to, że mniej niszczycielskim sposobem na to jest przejście w EF7 ("Data Motion") lub możesz napisać dużo ręcznego sql podczas migracji, aby utworzyć tabele tymczasowe i przenieść dane dookoła, jeśli chcesz unikaj utraty istniejących danych w tabeli.

EDYCJA: W zależności od scenariusza Migracja EF może nie odtworzyć tabeli - jeśli klasa już istnieje i jest już dodana do DbContext, po prostu ją upuści i pozostanie w tym miejscu, co oznacza, że ​​ręczna migracja musi nie tylko spaść ale także stwórz stół. Nie jest to wielka sprawa, ponieważ kod źródłowy EF Migrations generuje dla ciebie z migracji add, będzie tworzyć te instrukcje dla ciebie, ale jest trochę więcej kodu do sprawdzenia na problemy.

+0

To zadziałało dla mnie świetnie. Dzięki. – BrainSlugs83

4

Jest to właściwe rozwiązanie, ale tylko dla nowego stołu. Jeśli zmienisz opcję generowania bazy danych dla istniejącej tabeli, migracje EF nie będą mogły wykonać tej zmiany, a twoja kolumna QuoteId jest nadal oznaczona jako Identity w bazie danych.

+0

Dokumenty na IDENTITY_INSERT nie określają takiego ograniczenia, a w rzeczywistości w surowym SQL mogę je włączać i wyłączać dowolnie długo po utworzeniu tabeli i podać wartości dla PK. http://msdn.microsoft.com/en-us/library/ms188059.aspx Podkreślają, że co najwyżej jedna tabela może mieć tę funkcję włączoną na sesję, co oznacza, że ​​muszę ją przełączać nie za pomocą Migracji, ale raczej tuż przed INSERT następnie wyłącz go, co jest dość brzydkie. Wygląda na to, że znalezienie sposobu na wyłączenie funkcji tożsamości byłoby lepsze .... –

+0

EF nie zapewnia bezpośredniego sposobu gry z ustawieniem "IDENTITY_INSERT". Moja oryginalna odpowiedź skierowała twoją grę za pomocą 'DatabaseGeneratedOption'. –

+0

Widzę, co próbujesz teraz powiedzieć. EF Migrations musi faktycznie upuścić tabelę, aby dokonać tej zmiany - może to być ograniczenie SQL Server. –

1

Nie mogłem rozwiązać tego problemu z Twoimi sugestiami, a następnie próbowałem odtworzyć całą bazę danych, ale to też nie działało.

Aby to naprawić, należy usunąć właściwość : true przy pierwszym (!) Utworzeniu kolumny (na przykład Initial-Migration).

Może to pomoże ktoś ..

+0

Tak, tak brzmi moja odpowiedź. –

+0

Scenariusz jest trochę trudniejszy, jak się domyślałem. Gdy automatyczne migracje są włączone, wystarczy mieć model (prawdopodobnie zmieniony) z DatabaseGeneratedOption.None ustawionym w kolumnie klucza podstawowego SET IDENTITY INSERT ON dla tabeli w transakcji. Jednak w przypadku ręcznej migracji przy użyciu metody pierwszego kodu migracja będzie miała tożsamość: prawdziwe atrybuty dla kolumn klucza głównego. To ustawienie nie jest ustawiane przez automatyczną migrację, dlatego powinno zostać wyeliminowane z metody migracji Up() przed utworzeniem bazy danych. –

Powiązane problemy