Wird es allgemein als schlechte Praxis angesehen, vom Benutzer erstellte Felder in einer Datenbank für eine Webanwendung zuzulassen?
Zum Beispiel erstelle ich eine Web-App für meine Frau, in der sie ihre eigenen Felder für verschiedene Artikel definieren möchte. Ich wollte ihr erlauben, Artikelkategorien zu erstellen und "Features" zu diesen Kategorien hinzuzufügen. Features sind nur Schlüssel / Werte, die als Zeichenfolgen gespeichert werden. Wenn sie beispielsweise eine Kategorie mit dem Namen "Audio-CDs" hätte, könnte sie Funktionen für Dinge wie "Künstler", "Titel" usw. hinzufügen. In einer anderen Kategorie wie "Möbel" könnte sie Funktionen für Dinge wie "Material" hinzufügen "(Holz, Kunststoff usw.) Dann kann jeder Artikel zu einer (oder mehreren) Kategorien gehören und diese Funktionen zum Artikel hinzufügen.
Ich kann Probleme feststellen, bei denen die Suche nach diesen Features Zeichenfolgenvergleiche erfordert, keine Validierung von Daten usw. Nach einer agilen Methodik ist es möglicherweise besser, sie nur mit neuen Kategorien und Attributen auszustatten und neue Tabellen zu erstellen während wir gehen. In meinem Beispiel ist es eine kleine Nutzerbasis (2 von uns) und die Menge der erstellten Datensätze wäre klein, also nicht schlecht.
Aber wie gehen die Leute im "echten Leben" generell damit um?
Antworten:
Wenn Sie zu "benutzerdefinierten Feldern" gelangen, wie sie häufig in Bug - Trackern, Kundenressourcenverwaltung und ähnlichen Geschäftstools zu finden sind, werden sie nicht mit einer Tabelle mit Bajillion - Feldern unterstützt (wenn dies der Fall ist, ist dies wahrscheinlich ein Problem seine eigene).
Stattdessen finden Sie Tabellenentwürfe für Entitätsattributwerte und das zugehörige Verwaltungstool zum Verwalten der gültigen Attribute.
Betrachten Sie die folgende Tabelle:
Dies ist, nachdem Sie einige Attribute hinzugefügt haben. Anstatt so zu
attr1
tun, als würde es lesenartist
odertracks
odergenre
oder welche Attribute das Ding hat. Und statt 5, was wäre, wenn es 50 wäre? Das ist natürlich nicht zu handhaben. Außerdem ist eine Aktualisierung des Modells und eine erneute Bereitstellung der Anwendung erforderlich, um ein neues Feld bearbeiten zu können. Nicht ideal.Betrachten Sie nun die folgende Tabellenstruktur:
Sie haben Ihr Ding mit seinen Grundgebieten. Sie haben zwei weitere Tische. Eins mit den Attributen. Jedes Feld ist eine Zeile in der
attr
Tabelle. Und dann gibt es dasthing_attr
mit einem Paar Fremdschlüsseln, die sich auf denthing
Tisch und denattr
Tisch beziehen . Und dies hat dann ein Wertefeld, in dem Sie den Wert des Feldes für diese Entität speichern.Und jetzt haben Sie eine Struktur, in der die ATTR-Tabelle zur Laufzeit aktualisiert und neue Felder hinzugefügt (oder entfernt) werden können, ohne dass dies erhebliche Auswirkungen auf die Gesamtanwendung hat.
Die Abfragen sind etwas komplexer und die Validierung wird auch komplexer (entweder flippige gespeicherte Prozeduren oder alle Clients). Es ist ein Kompromiss im Design.
Berücksichtigen Sie auch die Situation, in der Sie eines Tages eine Migration durchführen müssen und Sie zur Anwendung zurückkehren und feststellen, dass es jetzt ein halbes Dutzend oder mehr Attribute als das ursprünglich verteilte Schema gibt. Dies führt zu hässlichen Migrationen und Upgrades, bei denen die Entity Attribute Value-Tabelle bei korrekter Verwendung sauberer sein kann. (Nicht immer, kann aber sein.)
Wenn Sie mit der entsprechenden Version der nosql-Datenbank arbeiten, können Sie dies wahrscheinlich tun (beachten Sie, dass die entsprechende Version der nosql wahrscheinlich ein Schlüsselwertspeicher ist, also die EAV-Tabelle für die oben beschriebenen relationalen). ohne zu viel Mühe. Es enthält jedoch alle Kompromisse für nosql, die an anderer Stelle ausführlich beschrieben werden.
Wenn Sie stattdessen an einer relationalen Datenbank arbeiten, benötigen Sie das Schema. Das dynamische Hinzufügen der Spalte bedeutet, dass eine Teilmenge der folgenden Dinge zutrifft:
select *
und führen dann einen komplexen Code aus, um herauszufinden, was die Daten tatsächlich sind (siehe Javas ResultSetMetaData ) und diesen dann in einer Karte zu speichern ( oder ein anderer Datentyp - aber keine netten Felder im Code). Dies wirft dann einiges an Typ- und Typosicherheit weg, die Sie mit dem traditionellen Ansatz haben.hasdate
Feld zum Speichern eines Zeitstempels hinzufügen möchte, bereits wiehasdate
ein Boolescher Wert für ein erfolgreiches Match definiert ... und das Upgrade wird abgebrochen.varchar2
vstext
und dergleichen. Ihr Code zum Hinzufügen der Spalte funktioniert unter MySQL, jedoch nicht unter Postgres, Oracle oder SQL Server.delete * from students
, aber Sie können die Datenbank nicht auf schlimme Weise durcheinander bringen). Die Anzahl der Probleme, die beim Schemazugriff aufgrund eines Unfalls oder böswilliger Aktivitäten auftreten können, steigt in die Höhe.Das läuft wirklich darauf hinaus, "es nicht zu tun". Wenn Sie dies wirklich möchten, verwenden Sie ein bekanntes Muster der EAV-Tabellenstruktur oder eine Datenbank, die dieser Struktur vollständig zugeordnet ist. Lassen Sie nicht zu, dass Personen beliebige Felder in einer Tabelle erstellen. Die Kopfschmerzen sind es einfach nicht wert.
quelle
Das gut zu machen ist schwer.
Für eine einmalige Anwendung wie die, die Sie planen, können Sie natürlich einfach eine Spalte für jedes Feld hinzufügen und eine Benutzeroberfläche bereitstellen, die die Felddefinition für ungeübte Benutzer sicherer macht, als ihnen eine SQL-Befehlszeile zu geben. Sie können auch dem gefürchteten Muster " Entity-Attribute-Value" folgen , das eine klassische, wenn auch etwas beängstigende Antwort auf diese Art von Problem darstellt. Das Erstellen der Benutzeroberfläche zum Definieren von EAV-Feldern ist in der Regel sehr viel komplexer als für Datenbankspalten, und die Abfragen können ziemlich unübersichtlich werden. Bei einer großen Anzahl von Feldern ( dh Schemata mit sehr geringer Matrixdichte) ist dies möglicherweise die einzige Möglichkeit die Arbeit erledigt.
quelle
Ich bin in letzter Zeit auf ein ähnliches Kreuz gestoßen.
Ich habe 2 Tische gemacht.
Er ist alle deine Objekte. Sie setzen den Namen davon.
Und ein Typ dieses Objekts: - Für mich waren die verfügbaren Typen Inventar, Inventargegenstand, Büro.
Und das übliche Setup war n Elemente sind untergeordnet oder Inventar, das auch untergeordnet zu Office ist, und ich habe eine Verknüpfungstabelle verwendet, um Objekte miteinander zu verknüpfen
Die Einstellungstabelle enthält alle Feldnamen für diesen bestimmten Objekttyp und den Wert im Wert.
Beispielimmobilien von Büro
Ort, Telefon, Arbeitszeit
Und für Gegenstände
Alle diese Eigenschaften werden von Ihrem Modell erzwungen und in der Einstellungstabelle als separate Zeilen gespeichert. Verwenden Sie jedoch die Option "Ersetzen, nicht einfügen", um mehrere Zeilen für dasselbe Feld zu vermeiden.
Wann immer ich ein Büro haben möchte, lade ich es einfach mit all seinen Beziehungen und Einstellungen, in denen die Einstellungen object_I'd sind (angeforderte Objekte).
Danach schwenke ich alle Zeilen aus den Einstellungen und das wars.
Und falls ich wollte, dass eine Einstellung spezifisch für einen Artikel in einem Inventar ist (nicht global), setze ich object_I'd = Ich würde aus der object_objects-Beziehungstabelle und setze settings.type = relation_setting
Ich hoffe, Sie verstehen, was ich meine. Ich werde versuchen, die Antwort neu zu formatieren, wenn ich an einen Laptop komme
quelle
Nein, es ist keine schlechte Praxis. Es ist ziemlich verbreitet. In OO-Begriffen wird dies Vererbung genannt. Sie haben eine Basisklasse inventoryItem und zwei geerbte Klassen AudioCD und furniture.
Sie müssen entscheiden, wie Inventarartikel, AudioCD und Möbel in der Datenbank gespeichert werden.
Wenn eine einfache Abfrage für Sie am wichtigsten ist und DB-Space / Normalisierung keine Rolle spielt, würden Sie das Schema "Tabelle pro Hierarchie" implementieren.
Wenn Platz / Normalisierung für Sie am wichtigsten ist und kompliziertere Abfragen für Sie kein Problem darstellen, würden Sie das Schema "Tabelle pro Typ" implementieren.
Weitere Informationen finden Sie unter Vererbung von Dotnet-Tabellen pro Typ im Vergleich zu Tabellen pro Hierarchie oder Java-Hibernate .
quelle