środa, 30 maja 2012

MS SQL: cycles or multiple cascade paths

Często możemy spotkać się z błędem który brzmi w następujący sposób:

Msg 1785, Level 16, State 0, Line 55
Introducing FOREIGN KEY constraint 'FK_Comments_Users' on table 'Comments' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Msg 1750, Level 16, State 0, Line 55
Could not create constraint. See previous errors.
Co jest powodem tego błędu?
Najłatwiej rozważyć prostą sytuację:



Rozważać właściwie będziemy tylko trzy tabele Users, Articles oraz Comments.
Z diagramu wynika że użytkownik może mieć wiele komentarzy jak i artykułów. Artykuł może mieć wiele komentarzy i jednego autora. Tworząc klucze obce wydawało by się, że prawidłowym rozwiązaniem byłoby stworzenie następujących kluczy:

ALTER TABLE dbo.Articles
  
ADD CONSTRAINT FK_Articles_Users FOREIGN KEY(UserId)
  
REFERENCES dbo.Users(Id)
  
ON DELETE CASCADE
   ON UPDATE
NO ACTION;ALTER TABLE dbo.Comments
  
ADD CONSTRAINT FK_Comments_Articles FOREIGN KEY(ArticleId)
  
REFERENCES dbo.Articles(Id)
  
ON DELETE CASCADE
   ON UPDATE
NO ACTION;ALTER TABLE dbo.Comments
  
ADD CONSTRAINT FK_Comments_Users FOREIGN KEY(UserId)
  
REFERENCES dbo.Users(Id)
  
ON DELETE CASCADE
   ON UPDATE
NO ACTION;


Ostatni klucz jest tutaj kluczowy. Wydaje się logiczne, że jeżeli usuwam użytkownika, powinny zostać usunięte jego komentarze. Zapominamy o jednym. W momencie kiedy usuwamy użytkownika, są usuwane jego artykuły a następnie kaskadowo komentarze do nich. Nie ma potrzeby usuwania ich w sposób kaskadowy jeszcze z poziomu użytkownika.

Tak więc powyższe klucze powinny mieć postać:

ALTER TABLE dbo.Articles
  
ADD CONSTRAINT FK_Articles_Users FOREIGN KEY(UserId)
  
REFERENCES dbo.Users(Id)
  
ON DELETE CASCADE
   ON UPDATE
NO ACTION;
ALTER TABLE dbo.Comments
  
ADD CONSTRAINT FK_Comments_Articles FOREIGN KEY(ArticleId)
  
REFERENCES dbo.Articles(Id)
  
ON DELETE CASCADE
   ON UPDATE
NO ACTION;
ALTER TABLE dbo.Comments
  
ADD CONSTRAINT FK_Comments_Users FOREIGN KEY(UserId)
  
REFERENCES dbo.Users(Id)
  
ON DELETE NO ACTION
  
ON UPDATE NO ACTION;


Pytanie jeszcze może budzić operacja NO ACTION w przypadku instrukcji UPDATE. Nie jest ona tutaj wymagana. Dlaczego? Ponieważ nie przewiduje w aplikacji możliwości zmiany klucza głównego osoby - są to auto numerowane pola i nie będą zmieniane w przyszłości, gdyż wprowadzić mogłoby to więcej chaosu niż pożytku.

Brak komentarzy:

Prześlij komentarz