Mam problem, kiedy próbuję dodać ograniczenia do moich tabel. Wyskakuje mi błąd:
Wprowadzenie ograniczenia klucza obcego „FK74988DB24B3C886” w tabeli „Pracownik” może spowodować cykle lub wiele ścieżek kaskadowych. Podaj opcję ON DELETE NO ACTION lub ON UPDATE NO ACTION lub zmodyfikuj inne ograniczenia klucza obcego.
Moje ograniczenie jest między Code
stołem a employee
stołem. Code
Tabela zawiera Id
, Name
, FriendlyName
, Type
i Value
. employee
Posiada szereg pól, które kody referencyjne, tak że nie może być punktem odniesienia dla każdego typu kodu.
Potrzebuję, aby pola były ustawione na null, jeśli kod, do którego się odwołuje, zostanie usunięty.
Jakieś pomysły, jak mogę to zrobić?
sql
sql-server
constraints
Ricardo Altamirano
źródło
źródło
Odpowiedzi:
SQL Server wykonuje proste zliczanie ścieżek kaskadowych i zamiast próbować ustalić, czy rzeczywiście istnieją jakiekolwiek cykle, zakłada najgorsze i odmawia tworzenia akcji referencyjnych (CASCADE): możesz i nadal możesz tworzyć ograniczenia bez akcji referencyjnych. Jeśli nie możesz zmienić projektu (lub zrobienie tego naraziłoby rzeczy na szwank), powinieneś rozważyć użycie wyzwalaczy jako ostateczności.
Rozwiązanie FWIW ścieżek kaskadowych jest złożonym problemem. Inne produkty SQL po prostu zignorują problem i pozwolą na tworzenie cykli, w którym to przypadku będzie to wyścig, który nadpisze wartość jako ostatnią, prawdopodobnie z powodu ignorancji projektanta (np. ACE / Jet to robi). Rozumiem, że niektóre produkty SQL będą próbowały rozwiązać proste przypadki. Fakt pozostaje faktem, SQL Server nawet nie próbuje, zachowuje się wyjątkowo bezpiecznie, blokując więcej niż jedną ścieżkę, a przynajmniej tak mówi.
Microsoft sam zaleca użycie wyzwalaczy zamiast ograniczeń FK.
źródło
Typowa sytuacja z wieloma ścieżkami kaskadowymi będzie wyglądać tak: tabela główna z dwoma szczegółami, powiedzmy „Główna” i „Szczegół1” i „Szczegół2”. Oba szczegóły są usuwane kaskadowo. Jak dotąd żadnych problemów. Ale co, jeśli oba szczegóły mają relację jeden do wielu z inną tabelą (powiedz „SomeOtherTable”). SomeOtherTable ma kolumnę Detail1ID i kolumnę Detail2ID.
Innymi słowy: niektóre rekordy w SomeOtherTable są połączone z rekordami Detail1, a niektóre rekordy w SomeOtherTable są połączone z rekordami Detail2. Nawet jeśli jest zagwarantowane, że rekordy SomeOtherTable nigdy nie należą do obu Details, niemożliwe jest teraz kaskadowe usuwanie rekordów SomeOhterTable dla obu szczegółów, ponieważ istnieje wiele ścieżek kaskadowych od Master do SomeOtherTable (jedna przez Detail1 i jedna przez Detail2). Być może już to zrozumiałeś. Oto możliwe rozwiązanie:
Wszystkie pola identyfikatora są polami kluczowymi i automatycznymi przyrostami. Sedno tkwi w polach DetailMainId tabel Detail. Pola te są zarówno kluczowym, jak i referencyjnym ograniczeniem. Teraz można kaskadowo usuwać wszystko, usuwając tylko rekordy główne. Wadą jest to, że dla każdego rekordu detail1 ORAZ dla każdego rekordu detail2 musi istnieć również rekord DetailMain (który w rzeczywistości jest tworzony jako pierwszy, aby uzyskać poprawny i unikalny identyfikator).
źródło
Chciałbym zwrócić uwagę, że (funkcjonalnie) istnieje DUŻA różnica między cyklami i / lub wieloma ścieżkami w SCHEMACIE i DANYCH. Chociaż cykle i być może wielościeżki w DANYCH z pewnością mogą skomplikować przetwarzanie i powodować problemy z wydajnością (koszt „prawidłowej” obsługi), koszt tych charakterystyk w schemacie powinien być bliski zeru.
Ponieważ większość widocznych cykli w RDB występuje w strukturach hierarchicznych (schemat organizacyjny, część, podpunkt, itp.), To niefortunne jest, że SQL Server zakłada najgorsze; tj. cykl schematu == cykl danych. W rzeczywistości, jeśli używasz ograniczeń RI, nie możesz faktycznie zbudować cyklu w danych!
Podejrzewam, że problem wielościeżkowy jest podobny; tj. wiele ścieżek w schemacie niekoniecznie oznacza wiele ścieżek w danych, ale mam mniejsze doświadczenie z problemem wielościeżkowym.
Oczywiście jeśli SQL Server nie pozwalają cykle że to nadal podlegać głębokości 32, ale to chyba wystarczające dla większości przypadków. (Szkoda jednak, że to nie jest ustawienie bazy danych!)
Nie działają też reguły „Zamiast usuwania”. Przy drugiej wizycie w tabeli wyzwalacz jest ignorowany. Tak więc, jeśli naprawdę chcesz zasymulować kaskadę, będziesz musiał użyć procedur składowanych w obecności cykli. Wyzwalacz zamiast usuwania będzie działał jednak w przypadkach wielościeżkowych.
Celko sugeruje „lepszy” sposób przedstawiania hierarchii, który nie wprowadza cykli, ale są kompromisy.
źródło
Dostępny jest artykuł, w którym wyjaśniono, jak wykonać wiele ścieżek usuwania za pomocą wyzwalaczy. Może jest to przydatne w przypadku złożonych scenariuszy.
http://www.mssqltips.com/sqlservertip/2733/solving-the-sql-server-multiple-cascade-path-issue-with-a-trigger/
źródło
Po jego dźwiękach masz akcję OnDelete / OnUpdate na jednym z istniejących kluczy obcych, która zmodyfikuje tabelę kodów.
Tworząc ten klucz obcy, tworzysz cykliczny problem,
Np. Aktualizacja pracowników powoduje zmianę kodów przez działanie przy aktualizacji, powoduje zmianę pracowników przez działanie przy aktualizacji ... itd.
Jeśli opublikujesz swoje definicje tabel dla obu tabel i definicje klucza obcego / ograniczeń, powinniśmy być w stanie powiedzieć Ci, gdzie jest problem ...
źródło
Dzieje się tak, ponieważ Pracownik może mieć kolekcję innego podmiotu, która twierdzi, że kwalifikacje i kwalifikacje mogą mieć inną kolekcję Uniwersytety, np
}
}
}
W DataContext mogłoby to wyglądać jak poniżej
}
w tym przypadku istnieje łańcuch od pracownika do kwalifikacji i od kwalifikacji do uniwersytetów. Więc rzucał mi ten sam wyjątek.
U mnie zadziałało, kiedy się zmieniłem
Do
źródło
Wyzwalacz jest rozwiązaniem tego problemu:
źródło
To jest błąd typu zasad wyzwalacza bazy danych. Wyzwalacz jest kodem i może dodawać inteligencje lub warunki do relacji kaskadowej, na przykład kaskadowej delecji. Może zajść potrzeba wyspecjalizowania powiązanych opcji tabel w tym zakresie, takich jak Wyłączanie CascadeOnDelete :
Lub całkowicie wyłącz tę funkcję:
źródło
Moje rozwiązanie tego problemu napotkane przy użyciu ASP.NET Core 2.0 i EF Core 2.0 polegało na wykonaniu następujących czynności w kolejności:
Uruchom
update-database
polecenie w konsoli zarządzania pakietami (PMC), aby utworzyć bazę danych (powoduje to błąd „Wprowadzenie ograniczenia klucza obcego ... może powodować cykle lub wiele ścieżek kaskadowych”).Uruchom
script-migration -Idempotent
polecenie w PMC, aby utworzyć skrypt, który można uruchomić niezależnie od istniejących tabel / ograniczeńWeź wynikowy skrypt, znajdź
ON DELETE CASCADE
i zamień naON DELETE NO ACTION
Wykonaj zmodyfikowany kod SQL w bazie danych
Teraz Twoje migracje powinny być aktualne, a usuwanie kaskadowe nie powinno mieć miejsca.
Szkoda, że nie mogłem znaleźć żadnego sposobu na zrobienie tego w Entity Framework Core 2.0.
Powodzenia!
źródło