2012-04-19 8 views
7

Mam unikalne ograniczenie dla kolumny tabeli Navigations o nazwie Index. Mam dwie jednostki Navigation i chcę zamienić ich wartości Index.Zamiana wartości z ograniczeniem unikalnym w Entity Framework

Po wywołaniu db.SaveChanges generuje wyjątek wskazujący, że naruszono unikalne ograniczenie. Wydaje się, że EF aktualizuje jedną wartość, a następnie drugą, naruszając tym samym ograniczenie.

Czy nie powinna aktualizować ich zarówno w transakcji, a następnie próbuje zatwierdzić, gdy wartości są uporządkowane, a nie narusza ograniczenia?

Czy istnieje sposób obejścia tego bez użycia wartości tymczasowych?

+1

Czy możesz pokazać jako kod? – Likurg

+0

potrzebujesz tu wartości tymczasowych, aktualizacja jest samodzielną operacją. więc zawsze dojdzie do naruszenia ograniczeń, jedyną opcją jest wyłączenie ograniczeń dla operacji. –

Odpowiedz

9

To nie problem EF, ale problem bazy danych SQL, ponieważ polecenia aktualizacji są wykonywane sekwencyjnie. Transakcja nie ma z tym nic wspólnego - wszystkie ograniczenia są sprawdzane dla każdego polecenia, a nie dla każdej transakcji. Jeśli chcesz zamienić unikalne wartości, potrzebujesz więcej kroków, w których użyjesz dodatkowych fałszywych wartości, aby uniknąć tej sytuacji.

+0

Wydaje się to niebezpieczne, ponieważ istnieje możliwość wystąpienia problemów z równoczesnymi żądaniami z wykorzystaniem tej samej fałszywej wartości lub może być to fałszywa wartość, która również narusza ograniczenie. Czy istnieje "najlepsza praktyka" w tej sytuacji, o której wiesz? –

+1

Można także usuwać stare rekordy i tworzyć nowe. Próbowałbym tego przede wszystkim uniknąć.Jest to sytuacja, w której unikalne ograniczenie nie pasuje do potrzeb logiki aplikacji. –

+0

Wystarczająco fair. Po prostu usunę unikalne ograniczenie z bazy danych. Nie spowoduje żadnych problemów w przypadku duplikatów. Jeśli tak, to po prostu będą w niewiarygodnej kolejności, gdy są wyświetlane na pasku nawigacji. –

2

Można wykonać zapytanie SQL zwyczaj, aby zamienić wartości, tak:

update Navigation 
set valuecolumn = 
     case 
      when id=1 then 'value2' 
      when id=2 then 'value1' 
     end 
where id in (1,2) 

Jednak Entity Framework nie może tego zrobić, ponieważ jest to poza zakresem ORM. Po prostu wykonuje sekwencyjne instrukcje dla każdej zmienionej jednostki, jak opisał Ladislav w swojej odpowiedzi.

Inną możliwością jest zniesienie ograniczenia UNIQUE w bazie danych i korzystanie z aplikacji w celu poprawnego egzekwowania tego ograniczenia. W takim przypadku EF może zapisać zmiany dokładnie, ale w zależności od scenariusza może nie być to możliwe.

3

Istnieje kilka podejść. Niektóre z nich są omówione w innych odpowiedziach i komentarzach, ale pod względem kompletności, wymienię je tutaj (zauważ, że jest to tylko lista, która burzy mózgów i może to nie wszystko, co "kompletne").

  1. Wykonaj wszystkie aktualizacje w jednym poleceniu. Przykładem tego jest W0lf's answer.
  2. Wykonaj dwa zestawy aktualizacji - jeden do zamiany wszystkich wartości na ujemną z zamierzonej wartości, a następnie drugi do zamiany z ujemnego na dodatni. Działa to na założeniach, że wartości ujemne nie są blokowane przez inne ograniczenia i że nie są to wartości, które będą miały zapisy inne niż te w stanie przejściowym.
  3. Dodaj dodatkową kolumnę - na przykład IsUpdating - ustaw ją na wartość true w pierwszym zestawie aktualizacji, w którym wartości zostały zmienione, a następnie ustaw ponownie na wartość false w drugim zestawie aktualizacji. Zamień unikalne ograniczenie dla przefiltrowanego, unikalnego indeksu, który ignoruje rekordy, w których IsUpdating ma wartość true.
  4. Usuń wiązanie i postępuj z duplikatami wartości.
+0

Pomysł ustawienia ujemnego, a następnie z powrotem na pozytywny był sprytny i zrobił mi lewę. Dzięki! – jslatts