13

Czytałem niektóre Bill Karwin's odpowiedzi na temat single table inheritance i że to byłoby dobre podejście do konfiguracji Zastanawiam:Jak wymusić integralność referencyjną w dziedziczeniu z pojedynczego stołu?

Playlist 
-------- 
id AUTO_INCREMENT 
title 

TeamPlaylist 
------------ 
id REFERENCES Playlist.id 
teamId REFERENCES Team.id 

UserPlaylist 
------------ 
id REFERENCES Playlist.id 
userId REFERENCES User.id 

PlaylistVideo 
------------- 
id 
playlistId REFERENCES Playlist.id 
videoId REFERENCES Video.id 

Wszystkie opcje CASCADE są ustawione na DELETE która będzie działać poprawnie, gdy jest Playlist usunięto jednak, co się stanie, jeśli usunięto User lub?

tj. Jeśli zostanie usunięta User, wiersze w UserPlaylist zostaną usunięte, ale pozostaną wiersze z odniesieniami w Playlist i PlaylistVideo. Zastanowiłem się nad wymuszeniem tego jako TRIGGER AFTER DELETE, ale nie można się dowiedzieć, czy wystąpiło żądanie usunięcia, ponieważ usunięto Playlist lub usunięto User.

Jaki jest najlepszy sposób na egzekwowanie uczciwości w tej sytuacji?

Edit (Pod warunkiem, ERD)

enter image description here

+1

Nie rozumiem, w jaki sposób UserPlaylist może być dziedziczeniem listy odtwarzania. Czy nie powinien to być tabela relacji? – Sebas

+0

Nie rozumiem twojego pytania. UserPlaylist jest powiązana z Playlistą tylko dlatego, że id pochodzi z Playlist.id. Oto kilka pytań na temat dziedziczenia pojedynczego stołu - http://stackoverflow.com/a/3383320/47278 –

+0

Powód, dla którego nie chcesz, aby usunięty użytkownik usuwał listy odtwarzania i wiersze wideo z listy odtwarzania, ponieważ mogliby się również odwoływać przez inne listy użytkowników lub teamplaylist. – WebChemist

Odpowiedz

3

Moim zdaniem, problemem jest to, że User i Team stoliki są te, które powinny mieć tabeli supertypem (takich jak Party) nie tabelach playlisty.

Jak już zauważyłeś, robienie "dziedziczenia stołu" na listach odtwarzania wiąże się z karami, gdy próbujesz dowiedzieć się, co usunąć. Wszystkie te problemy ustąpią, gdy przeniesiesz dziedziczenie do poziomu użytkownika/zespołu.

Możesz zobaczyć this answer for more detail about supertyping/subtyping.

Przykro mi, że nie dostarczam kodu, ponieważ nie znam składni MySQL na pamięć.

Podstawową koncepcją jest to, że tabela supertype pozwala na wdrożenie typu polimorfizmu bazy danych. Kiedy stół, z którym pracujesz, musi łączyć się z dowolną z grupy podtypów, po prostu sprawisz, że FK będzie wskazywał na nadtyp, a to automatycznie dostarczy ci pożądanego "tylko jednego z nich na raz" ograniczenia biznesowe. Typ super ma relację "jeden do zera lub jeden" z każdą z tabel podtypów, a każda tabela podtypów używa tej samej wartości w PK jako PK z tabeli nadtypu.

W bazie danych, mając tylko jedną tabelę Playlist z FK na Party (PartyID), łatwo wymusić regułę biznesową na poziomie bazy danych bez wyzwalaczy.

+0

To dobry punkt i dobry pomysł. W tym systemie jednak Zespół znacznie różni się od Użytkownika. na przykład. Użytkownik może się zalogować, Zespół nie może. Jest to istniejący system w produkcji (podczas gdy listy odtwarzania są nowe). Gdybym budował go od zera, prawdopodobnie byłby to właściwy sposób. Ale muszę przemyśleć to, czy warto byłoby przejść na tę konfigurację (np. Zespoły i użytkownicy mają obecnie nakładające się identyfikatory). Ale dzięki za sugestię. –

+0

Po to są tabele podtypów: sposoby, w jakie się różnią. Prawdziwym problemem przy zmianie jest aktualizacja identyfikatorów jednego z zestawów wraz z zrzucaniem i odtwarzaniem wiązań. Ale myślę, że to jest warte zachodu. :) – ErikE

+0

Dziękujemy za wybranie odpowiedzi! Co skłoniło cię do podjęcia decyzji, to była droga? – ErikE

4

OK widzę, co chcesz tutaj ... to, co chcesz zrobić, to uruchomić kwerendę jak

DELETE FROM playlist 
WHERE  id 
NOT IN  (
    SELECT id 
    FROM UserPlayList 
    UNION 
    SELECT id 
    FROM TeamPlayList 
) 

po albo wiersz jest usunięte z użytkowników lub zespołów

11

Co możesz zrobić, to wprowadzić wyzwalacze na swoich tabelach Users i Team, które są wykonywane Ute gdy wiersze zostaną usunięte z albo:

stół użytkownika:

DELIMITER $$ 
CREATE TRIGGER user_playlist_delete 
BEFORE DELETE ON User FOR EACH ROW 
BEGIN 
    DELETE a FROM Playlist a 
    INNER JOIN UserPlaylist b ON a.id = b.id AND b.userId = OLD.id; 
END$$ 
DELIMITER ; 

tabeli zespołu:

DELIMITER $$ 
CREATE TRIGGER team_playlist_delete 
BEFORE DELETE ON Team FOR EACH ROW 
BEGIN 
    DELETE a FROM Playlist a 
    INNER JOIN TeamPlaylist b ON a.id = b.id AND b.teamId = OLD.id; 
END$$ 
DELIMITER ; 

Co te wyzwalacze zrobi to za każdym razem rekord zostanie usunięty z jednego z tych tabel, operacja DELETE zostanie automatycznie uruchomiona na tabeli Playlists przy użyciu id, która ma zostać usunięta (poprzez połączenie wewnętrzne).

Testowałem to i działa świetnie.

+0

genialne rozwiązanie. nie testowałem tego myslef, ale wygląda solidnie.+1 – techtheatre

+0

Dobry pomysł Zane. Z jakiegoś powodu nie myślałem o umieszczeniu wyzwalacza na tabelach użytkowników lub zespołów - tylko tabele UserPlaylist lub TeamPlaylist. –

+0

Nie sądzę, że jest to najlepszy sposób na rozwiązanie problemu ... – ErikE

1

Odpowiedź Zane Bien jest dość oczywista. & superb.Ale mam pomysł na zrobienie tego bez użycia wyzwalacza, ponieważ wyzwalacz ma wiele problemów.

Czy używasz dowolnego języka programowania? Jeśli tak to,

pomocą pojedynczego transaction i dokonać bazie auto commit false

napisać DELETE dla przywoływanych wierszy w listy odtwarzania i PlaylistVideo. Ręcznie musisz najpierw napisać to zapytanie, używając tego identyfikatora referencyjnego (z warunkiem) i uruchomić go.

Teraz przygotuj kolejną kwerendę dla głównego zadania, tj. Usuń użytkownika, a wiersze listy UserPlaylist zostaną automatycznie usunięte (z powodu opcji CASCADE DELETE).Teraz uruchom drugie zapytanie i commit.

Wreszcie dokonaj transakcji auto commit true.

Działa z powodzeniem, mam nadzieję, że będzie pomocna.

Powiązane problemy