Nehmen wir an, ich habe eine Artikeltabelle:
CREATE TABLE items
(
item serial PRIMARY KEY,
...
);
Nun möchte ich das Konzept der "Berechtigungen" für jedes Element einführen (bitte beachten Sie, dass es sich hier nicht um Datenbankzugriffsberechtigungen handelt, sondern um Geschäftslogikberechtigungen für dieses Element). Jedes Element verfügt über Standardberechtigungen und Benutzerberechtigungen, die die Standardberechtigungen überschreiben können.
Ich habe versucht, dies auf verschiedene Arten umzusetzen, und habe die folgenden Lösungen gefunden, bin mir aber nicht sicher, welche die beste ist und warum:
1) Die Boolesche Lösung
Verwenden Sie für jede Berechtigung eine boolesche Spalte:
CREATE TABLE items
(
item serial PRIMARY KEY,
can_change_description boolean NOT NULL,
can_change_price boolean NOT NULL,
can_delete_item_from_store boolean NOT NULL,
...
);
CREATE TABLE item_per_user_permissions
(
item int NOT NULL REFERENCES items(item),
user int NOT NULL REFERENCES users(user),
PRIMARY KEY(item, user),
can_change_description boolean NOT NULL,
can_change_price boolean NOT NULL,
can_delete_item_from_store boolean NOT NULL,
...
);
Vorteile : Jede Berechtigung ist benannt.
Nachteile : Es gibt Dutzende von Berechtigungen, die die Anzahl der Spalten erheblich erhöhen, und Sie müssen sie zweimal definieren (einmal in jeder Tabelle).
2) Die ganzzahlige Lösung
Verwenden Sie eine Ganzzahl und behandeln Sie sie als Bitfeld (dh Bit 0 ist für can_change_description
, Bit 1 ist für can_change_price
usw. und verwenden Sie bitweise Operationen, um Berechtigungen festzulegen oder zu lesen).
CREATE DOMAIN permissions AS integer;
Vorteile : sehr schnell.
Nachteile : Sie müssen sowohl in der Datenbank als auch in der Front-End-Schnittstelle nachverfolgen , welches Bit für welche Berechtigung steht.
3) Die Bitfield-Lösung
Wie 2), jedoch verwenden bit(n)
. Wahrscheinlich die gleichen Vor- und Nachteile, vielleicht etwas langsamer.
4) Die Enum-Lösung
Verwenden Sie einen Aufzählungstyp für die Berechtigungen:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
Erstellen Sie dann eine zusätzliche Tabelle für Standardberechtigungen:
CREATE TABLE item_default_permissions
(
item int NOT NULL REFERENCES items(item),
perm permission NOT NULL,
PRIMARY KEY(item, perm)
);
und ändern Sie die Definitionstabelle pro Benutzer in:
CREATE TABLE item_per_user_permissions
(
item int NOT NULL REFERENCES items(item),
user int NOT NULL REFERENCES users(user),
perm permission NOT NULL,
PRIMARY KEY(item, user, perm)
);
Vorteile : Einfache Benennung einzelner Berechtigungen (Bitpositionen müssen nicht bearbeitet werden).
Nachteile : Auch wenn Sie nur die Standardberechtigungen abrufen, müssen Sie auf zwei zusätzliche Tabellen zugreifen: erstens auf die Standardberechtigungstabelle und zweitens auf den Systemkatalog, in dem die Enum-Werte gespeichert sind.
Insbesondere, weil die Standardberechtigungen für jede einzelne Seitenansicht dieses Elements abgerufen werden müssen , kann die Leistung der letzten Alternative erheblich beeinträchtigt werden.
5) Die Enum Array Lösung
Entspricht 4), aber verwenden Sie ein Array, um alle (Standard-) Berechtigungen zu speichern:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
Vorteile : Einfache Benennung einzelner Berechtigungen (Bitpositionen müssen nicht bearbeitet werden).
Nachteile : Bricht die 1. Normalform und ist etwas hässlich. Nimmt eine beträchtliche Anzahl von Bytes in Folge ein, wenn die Anzahl der Berechtigungen groß ist (ungefähr 50).
Können Sie sich andere Alternativen vorstellen?
Welcher Ansatz sollte gewählt werden und warum?
Bitte beachten Sie: Dies ist eine modifizierte Version einer Frage, die zuvor bei Stackoverflow gepostet wurde .
bigint
Felder (jedes für 64 Bit) oder eine Bitfolge auswählen. Ich habe ein paar verwandte Antworten auf SO geschrieben, die hilfreich sein könnten.