Datenbankschema für Entitäten mit zwei möglichen Eigentümer- / Elterntypen?

8

Ich verwende PostgreSQL mit Sequelize als ORM.

Ich habe einen Typ User. Der zweite Typ ist Group, dem über eine GroupMembershipsTabelle eine beliebige Anzahl von Benutzern zugeordnet werden kann . Users kann auch eine beliebige Anzahl von Groups besitzen.

Mein dritter Typ Playlistkann entweder zu einem UserODER zu einem gehören group. Was wäre der beste Weg, um ein Schema für diesen Typ so zu entwerfen, dass es entweder einen Eigentümertyp oder einen der beiden haben kann?

Bei meinem ersten Durchgang habe ich beide Assoziationen erstellt, aber jeweils nur eine. Dies könnte möglicherweise funktionieren, scheint aber hackig und macht Abfragen schwierig.

Zusätzliche Information

Hier sind meine Antworten auf die von MDCCL über Kommentare gestellten Klärungsanfragen:

(1) Wenn eine Wiedergabeliste einer bestimmten Gruppe gehört , kann man sagen, dass diese Wiedergabeliste mit einem bis vielen Benutzern zusammenhängt , solange sie Mitglieder einer solchen Gruppe sind , oder?

Ich glaube, dass dies technisch wahr ist, aber diese Eins-zu-Viele-Assoziation existiert nicht explizit.

(2) Ist es also möglich, dass eine bestimmte Wiedergabeliste gleichzeitig einer von mehreren Gruppen gehört ?

Nein, es sollte nicht möglich sein, dass ein PlaylistEins-zu-Viele gehört Groups.

(3) Ist es möglich, dass eine bestimmte Wiedergabeliste einer von vielen Gruppen und gleichzeitig einem von vielen Benutzern gehört , die nicht Mitglieder einer solchen Gruppe sind ?

Nein, denn wie in (2) sollte ein Eins-zu-Viele von Playlistbis Groupnicht existieren. Wenn a Playlistim Besitz von a ist, gehört Groupes nicht im Besitz von a Userund umgekehrt. Jeweils nur ein Eigentümer.

(4) Mit welchen Eigenschaften werden eine Gruppe , ein Benutzer und eine Wiedergabeliste eindeutig identifiziert ?

Sie haben jeweils einen Ersatzprimärschlüssel ( id) sowie einen natürlichen Schlüssel (wenn auch keinen Primärschlüssel). Diese sind slugfür Groupund Playlistund usernamefür User.

(5) Könnte eine bestimmte Wiedergabeliste einen Besitzerwechsel erleiden ?

Obwohl ich (zumindest anfangs) nicht vorhabe, dass dies ein Feature ist, könnte dies hypothetisch auftreten.

(6) Welche Bedeutung haben die Attribute Group.Slug und Playlist.Slug ? Sind ihre Werte stabil genug, um als Primärschlüssel definiert zu werden, oder ändern sie sich sehr oft? Die Werte dieser beiden Eigenschaften müssen zusammen mit User.Username eindeutig sein. Richtig?

Dies slugsind eindeutige Versionen der jeweiligen Entität in Kleinbuchstaben und mit Bindestrich title. Zum Beispiel würde ein groupmit titleder slug'Testgruppe' die 'Testgruppe' haben. Duplikate werden mit inkrementellen Ganzzahlen angehängt. Dies würde sich jederzeit titleändern. Ich glaube, das bedeutet, dass sie keine großartigen Primärschlüssel machen würden? Ja, slugsund usernamessind in ihren jeweiligen Tabellen eindeutig.

Jakemmarsh
quelle

Antworten:

9

Wenn ich Ihre Spezifikationen richtig verstehe, beinhaltet Ihr Szenario - unter anderen wichtigen Aspekten - eine Supertyp-Subtyp- Struktur.

Ich werde im Folgenden beispielhaft erläutern, wie (1) es auf der konzeptionellen Abstraktionsebene modelliert und anschließend (2) in einem DDL-Design auf logischer Ebene dargestellt wird .

Geschäftsregeln

Die folgenden konzeptionellen Formulierungen gehören zu den wichtigsten Regeln in Ihrem Geschäftskontext:

  • Eine Wiedergabeliste gehört zu einem bestimmten Zeitpunkt entweder genau einer Gruppe oder genau einem Benutzer
  • Eine Wiedergabeliste kann zu unterschiedlichen Zeitpunkten einer oder mehreren Gruppen oder Benutzern gehören
  • Ein Benutzer besitzt null, eins oder viele Wiedergabelisten
  • Eine Gruppe besitzt null, eins oder viele Wiedergabelisten
  • Eine Gruppe besteht aus einem bis vielen Mitgliedern (die Benutzer sein müssen ).
  • Ein Benutzer kann Mitglied von Null-Eins-oder-Viele- Gruppen sein .
  • Eine Gruppe besteht aus einem bis vielen Mitgliedern (die Benutzer sein müssen ).

Da die Assoziationen oder Beziehungen (a) zwischen Benutzer und Wiedergabeliste und (b) zwischen Gruppe und Wiedergabeliste ziemlich ähnlich sind, zeigt diese Tatsache, dass Benutzer und Gruppe sich gegenseitig ausschließende Entitätsuntertypen von Partei 1 sind , die wiederum ihren Entitäts-Supertyp - Supertyp - sind. Subtyp-Cluster sind klassische Datenstrukturen, die in konzeptionellen Schemata sehr unterschiedlicher Art entstehen. Auf diese Weise können zwei neue Regeln geltend gemacht werden:

  • Eine Party wird nach genau einem PartyType kategorisiert
  • Eine Partei ist entweder eine Gruppe oder ein Benutzer

Und vier der vorherigen Regeln müssen als nur drei umformuliert werden:

  • Eine Wiedergabeliste gehört zu einem bestimmten Zeitpunkt genau einer Partei
  • Eine Wiedergabeliste kann zu unterschiedlichen Zeitpunkten im Besitz von einer bis mehreren Parteien sein
  • Eine Partei besitzt null, eins oder viele Wiedergabelisten

Expository IDEF1X-Diagramm

Das in Abbildung 1 gezeigte IDEF1X 2- Diagramm konsolidiert alle oben genannten Geschäftsregeln zusammen mit anderen, die relevant erscheinen:

Abbildung 1 - IDEF1X-Diagramm für Besitzer von Wiedergabelisten

Wie gezeigt, werden Gruppe und Benutzer als Untertypen dargestellt, die durch die jeweiligen Linien und das exklusive Symbol mit Party , dem Supertyp, verbunden sind.

Die Party.PartyTypeCode- Eigenschaft steht für den Subtyp- Diskriminator , dh sie gibt an, welche Art von Subtyp-Instanz ein bestimmtes Supertyp-Vorkommen ergänzen muss.

Außerdem ist Party über die OwnerId- Eigenschaft mit der Wiedergabeliste verbunden, die als AUSLÄNDISCHER SCHLÜSSEL dargestellt wird, der auf Party.PartyId verweist . Auf diese Weise verknüpft die Partei (a) die Wiedergabeliste mit (b) der Gruppe und (c) dem Benutzer .

Da eine bestimmte Party- Instanz entweder eine Gruppe oder ein Benutzer ist , kann eine bestimmte Wiedergabeliste mit höchstens einem Subtyp-Vorkommen verknüpft werden.

Illustratives Layout auf logischer Ebene

Das zuvor erläuterte IDEF1X-Diagramm diente mir als Plattform zum Erstellen der folgenden logischen SQL-DDL-Anordnung (und ich habe Anmerkungen als Kommentare bereitgestellt, in denen mehrere Punkte von besonderer Relevanz hervorgehoben wurden - z. B. die Einschränkungsdeklarationen -):

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- Also, you should make accurate tests to define the 
-- most convenient INDEX strategies based on the exact 
-- data manipulation tendencies of your business domain.

-- As one would expect, you are free to utilize 
-- your preferred (or required) naming conventions. 

CREATE TABLE PartyType ( -- Represents an independent entity type.
    PartyTypeCode CHAR(1)  NOT NULL,
    Name          CHAR(30) NOT NULL,  
    --
    CONSTRAINT PartyType_PK PRIMARY KEY (PartyTypeCode),
    CONSTRAINT PartyType_AK UNIQUE      (Name)  
);

CREATE TABLE Party ( -- Stands for the supertype.
    PartyId         INT       NOT NULL,
    PartyTypeCode   CHAR(1)   NOT NULL, -- Symbolizes the discriminator.
    CreatedDateTime TIMESTAMP NOT NULL,  
    --
    CONSTRAINT Party_PK            PRIMARY KEY (PartyId),
    CONSTRAINT PartyToPartyType_FK FOREIGN KEY (PartyTypeCode)
        REFERENCES PartyType (PartyTypeCode)
);

CREATE TABLE UserProfile ( -- Denotes one of the subtypes. 
    UserId     INT      NOT NULL, -- To be constrained as both (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    UserName   CHAR(30) NOT NULL,  
    FirstName  CHAR(30) NOT NULL,
    LastName   CHAR(30) NOT NULL,
    GenderCode CHAR(3)  NOT NULL,
    BirthDate  DATE     NOT NULL,
    --
    CONSTRAINT UserProfile_PK  PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK1 UNIQUE ( -- Multi-column ALTERNATE KEY.
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    ),
    CONSTRAINT UserProfile_AK2       UNIQUE (UserName), -- Single-column ALTERNATE KEY.
    CONSTRAINT UserProfileToParty_FK FOREIGN KEY (UserId)
        REFERENCES Party (PartyId)
);

CREATE TABLE MyGroup ( -- Represents the other subtype.
    GroupId INT      NOT NULL, -- To be constrained as both (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    Title   CHAR(30) NOT NULL,
    --
    CONSTRAINT Group_PK        PRIMARY KEY (GroupId),
    CONSTRAINT Group_AK        UNIQUE      (Title), -- ALTERNATE KEY.
    CONSTRAINT GroupToParty_FK FOREIGN KEY (GroupId)
        REFERENCES Party (PartyId)
);

CREATE TABLE Playlist ( -- Stands for an independent entity type.
    PlaylistId      INT       NOT NULL,
    OwnerId         INT       NOT NULL,  
    Title           CHAR(30)  NOT NULL,
    CreatedDateTime TIMESTAMP NOT NULL,  
    --
    CONSTRAINT Playlist_PK     PRIMARY KEY (PlaylistId),
    CONSTRAINT Playlist_AK     UNIQUE      (Title),  -- ALTERNATE KEY.
    CONSTRAINT PartyToParty_FK FOREIGN KEY (OwnerId) -- Establishes the relationship with (a) the supertype and (b) through the subtype with (c) the subtypes.
        REFERENCES Party (PartyId)
);

CREATE TABLE GroupMember ( -- Denotes an associative entity type.
    MemberId       INT       NOT NULL, 
    GroupId        INT       NOT NULL,
    IsOwner        BOOLEAN   NOT NULL,    
    JoinedDateTime TIMESTAMP NOT NULL,
    --        
    CONSTRAINT GroupMember_PK              PRIMARY KEY (MemberId, GroupId), -- Composite PRIMARY KEY.
    CONSTRAINT GroupMemberToUserProfile_FK FOREIGN KEY (MemberId)
        REFERENCES UserProfile (UserId),
    CONSTRAINT GroupMemberToMyGroup_FK     FOREIGN KEY (GroupId)
        REFERENCES MyGroup (GroupId)  
);

Natürlich können Sie eine oder mehrere Anpassungen vornehmen, damit alle Merkmale Ihres Geschäftskontexts mit der erforderlichen Genauigkeit in der tatsächlichen Datenbank dargestellt werden.

Hinweis : Ich habe das obige logische Layout auf dieser db <> -Fiedel und auch auf dieser SQL-Geige getestet , die beide unter PostgreSQL 9.6 "ausgeführt" werden, damit Sie sie "in Aktion" sehen können.

Die Schnecken

Wie Sie sehen können, habe ich weder in die DDL-Deklarationen Group.Slugnoch Playlist.Slugals Spalten aufgenommen. Dies liegt daran, dass in Übereinstimmung mit Ihrer folgenden Erklärung

Dies slugsind eindeutige Versionen der jeweiligen Entität in Kleinbuchstaben und mit Bindestrich title. Zum Beispiel würde ein groupmit titleder slug'Testgruppe' die 'Testgruppe' haben. Duplikate werden mit inkrementellen Ganzzahlen angehängt. Dies würde sich jederzeit titleändern. Ich glaube, das bedeutet, dass sie keine großartigen Primärschlüssel machen würden? Ja, slugsund usernamessind in ihren jeweiligen Tabellen eindeutig.

man kann daraus schließen, dass ihre Werte ableitbar sind (dh sie müssen in Bezug auf die entsprechenden Group.Titleund Playlist.TitleWerte berechnet oder berechnet werden, manchmal in Verbindung mit - ich nehme an, eine Art von systemgenerierten INTEGERs), daher würde ich diese Spalten nicht deklarieren in einer der Basistabellen als würden sie neue Unregelmäßigkeiten einzuführen.

Im Gegensatz dazu würde ich das produzieren Slugs

  • Vielleicht kann in einer Ansicht , die (a) die Ableitung solcher Werte in virtuellen Spalten enthält und (b) direkt in weiteren SELECT-Operationen verwendet werden kann - das Anhängen des INTEGER-Teils könnte beispielsweise durch Kombinieren des Werts von (1) erhalten werden. die Playlist.OwnerIdmit (2) den Zwischenbindestrichen und (3) dem Wert der Playlist.Title;

  • oder aufgrund des Anwendungsprogrammcodes den zuvor beschriebenen Ansatz (möglicherweise prozedural) nachahmen, sobald die relevanten Datensätze abgerufen und für die Interpretation durch den Endbenutzer formatiert wurden.

Auf diese Weise würde jede dieser beiden Methoden den Mechanismus der "Aktualisierungssynchronisation" vermeiden, der eingerichtet werden sollte, wenn die Slugsin Spalten von Basistabellen beibehalten werden.

Überlegungen zu Integrität und Konsistenz

Es ist wichtig zu erwähnen, dass (i) jede Party Zeile jederzeit durch (ii) das jeweilige Gegenstück in genau einer der Tabellen für die Untertypen ergänzt werden muss, die (iii) dem in der Party.PartyTypeCodeSpalte enthaltenen Wert „entsprechen“ müssen - den Diskriminator bezeichnen -.

Es wäre durchaus vorteilhaft, diese Art von Situation deklarativ durchzusetzen , aber keines der großen SQL-Datenbankverwaltungssysteme (einschließlich Postgres) hat die erforderlichen Instrumente bereitgestellt , um so vorzugehen. Daher ist das Schreiben von Verfahrenscode in ACID TRANSACTIONS bislang die beste Option, um sicherzustellen, dass die zuvor beschriebenen Umstände in Ihrer Datenbank immer erfüllt sind . Eine andere Möglichkeit wäre, auf TRIGGERS zurückzugreifen, aber sie neigen dazu, die Dinge sozusagen unordentlich zu machen.

Vergleichbare Fälle

Wenn Sie einige Analogien feststellen möchten, könnten Sie sich meine Antworten auf die (neueren) Fragen mit dem Titel ansehen

da werden vergleichbare szenarien diskutiert.


Endnoten

1 - Partei ist ein Begriff in rechtlichen Zusammenhängen verwendet werdenwenn entweder einem Bezug einzelne oder eine Gruppe von Personen , die eine einzelne Einheit zusammensetzen , so dass diesegeeignethatdie Konzepte der repräsentieren Benutzer und Gruppen in Bezug auf das Geschäftsumfeld in Frage.

2 Integration Definition für Information Modeling ( IDEF1X ) ist eine sehr empfehlenswerte Datenmodellierungstechnik, die als etabliert wurde Standard im Dezember 1993 von den Vereinigten Staaten National Institute of Standards and Technology (NIST). Es basiert fest auf (a) einigen der frühen theoretischen Arbeiten, die vom alleinigen Urheber des relationalen Modells verfasst wurden , dh Dr. EF Codd ; zu (b) dervon Dr. PP Chen entwickelten Entity-Relationship-Sicht ; und auch auf (c) der Logical Database Design Technique, erstellt von Robert G. Brown.

MDCCL
quelle
Ich habe keine Einschränkungen für die Partei gesehen, ist genau eine der Benutzer oder Gruppen
Jasen
Es sieht so aus, als hätte Ihr Kommentar mit den folgenden
MDCCL
Es ist wichtig zu erwähnen, dass (i) jede PartyZeile jederzeit durch (ii) das jeweilige Gegenstück in genau einer der für die Untertypen stehenden Tabellen ergänzt werden muss, die (iii) dem in der Tabelle enthaltenen Wert 'entsprechen' müssen Party.PartyTypeCodeSpalte - bezeichnet den Diskriminator - “.
MDCCL
Es wäre sehr vorteilhaft, eine solche Situation deklarativ durchzusetzen , aber keines der großen SQL-Datenbankverwaltungssysteme (einschließlich Postgres) hat die erforderlichen Instrumente bereitgestellt , um so vorzugehen. Daher ist das Schreiben von Verfahrenscode in ACID TRANSACTIONS bislang die beste Option, um sicherzustellen, dass die zuvor beschriebenen Umstände in Ihrer Datenbank immer erfüllt sind. Eine andere Möglichkeit wäre, auf TRIGGERS zurückzugreifen, aber sie neigen dazu, die Dinge sozusagen unordentlich zu machen . “
MDCCL
Daher würde ich gerne (hoffentlich bald), wenn Postgres beispielsweise ASSERTIONS liefert, die geltenden (deklarativen) Einschränkungen einbeziehen. Derzeit werden die beiden verfügbaren DBMS-Ansätze oben vorgeschlagen.
MDCCL