17

Używam Entity Framework, aby uzyskać dostęp do moich danych SQL. Mam pewne ograniczenia w schemacie bazy danych i zastanawiam się, jak obsługiwać wyjątki, które są spowodowane przez te ograniczenia.Entity Framework: Jak prawidłowo obsługiwać wyjątki, które występują z powodu ograniczeń SQL

Jako przykład, otrzymuję następujący wyjątek w przypadku, gdy dwóch użytkowników próbuje jednocześnie dodać (prawie) identyczną jednostkę do bazy danych.

System.Data.UpdateException 
"An error occurred while updating the entries. See the InnerException for details." 

(inner exception) System.Data.SqlClient.SqlException 
"Violation of UNIQUE KEY constraint 'Unique_GiftId'. Cannot insert duplicate key in object 'dbo.Donations'.\r\nThe statement has been terminated." 

Jak prawidłowo wychwycić ten wyjątek?

Brudny rozwiązanie:

catch (UpdateException ex) 
    { 
     SqlException innerException = ex.InnerException as SqlException; 
     if (innerException != null && innerException.Message.StartsWith("Violation of UNIQUE KEY constraint 'Unique_GiftId'")) 
     { 
      // handle exception here.. 
     } 
     else 
     { 
      throw; 
     } 
    } 

Teraz, gdy takie podejście działa, to ma pewne wady:

  • Brak typu bezpieczeństwa: Kod zależy od wiadomości wyjątek, który zawiera nazwę unikalna kolumna.
  • zależność od klas SqlClient (złamane abstrakcja)

Znasz lepsze rozwiązanie tego problemu? Dzięki za wszystkie informacje zwrotne ..

Uwaga: Nie chcę zakodować ograniczeń ręcznie w warstwie aplikacji, chcę mieć je w DB.

Odpowiedz

17

powinien być w stanie pułapka numer błędu SQL (który jest SqlException.Number)

W tym przypadku jest to 2627, która była zawsze taka sama dla SQL Server.

Jeśli chcesz abstrakcji, zawsze będziesz mieć pewną zależność od silnika bazy danych, ponieważ każdy z nich będzie generował różne numery i komunikaty wyjątków.

+0

OK, ale nawet jeśli używam tego identyfikatora, muszę przeanalizować komunikat wyjątku dla nazwy kolumny. – driAn

+0

@driAn: poprawne. SQL nie ma również natywnego mechanizmu do wiercenia, do którego wiązania lub kolumny, co oznacza, że ​​nie ma API lub coś takiego do odczytu. – gbn

2

Jednym ze sposobów jest sprawdzenie Errors property wewnętrznego wyjątku SqlException. Klasa SqlError ma numer Number property, który identyfikuje dokładny błąd. Zobacz tabelę master.dbo.sys dla listy wszystkich kodów błędów.

Oczywiście to nadal wiąże cię z serwerem SQL. Nie jestem świadomy sposobu, aby to zlikwidować, poza rolowaniem własnego "analizatora wyjątków EF".

0

Ten scenariusz nie powinien mieć miejsca, ponieważ klucz nie powinien być nigdy przypisywany jawnie podczas używania EF; raczej pozwalając kontekstowi przypisać odpowiedni. Jeśli jest to kwestia współbieżności, powinieneś zrobić aktualizację w zakresie transakcji.

Następnie, jeśli masz wyjątek UpdateException, możesz ponowić próbę aktualizacji ponownie. Możesz to bezpiecznie zrobić w zakresie transakcji i uzupełnić zakres tylko wtedy, gdy aktualizacja przyjdzie dokładnie. W tym scenariuszu szanse aktualizacji następnej godziny są większe niż pierwsze.

Powiązane problemy