2011-01-16 5 views
17

Ich arbeite an einem Editor, der seinen Benutzern ermöglicht, "Objekt" -Definitionen in Echtzeit zu erstellen. Eine Definition kann null oder mehr Eigenschaften enthalten. Eine Eigenschaft hat einen Namen und einen Typ. Sobald eine Definition erstellt wurde, kann ein Benutzer ein Objekt dieser Definition erstellen und die Eigenschaftswerte dieses Objekts festlegen.Schema zur Unterstützung dynamischer Eigenschaften

Also per Mausklick sollte der Benutzer zB. in der Lage sein, eine neue Definition namens "Bicycle" zu erstellen und die Eigenschaft "Size" vom Typ "Numeric" hinzuzufügen. Dann eine andere Eigenschaft namens "Name" vom Typ "Text" und dann eine andere Eigenschaft namens "Preis" vom Typ "Numerisch". Sobald dies erledigt ist, sollte der Benutzer in der Lage sein, ein paar "Fahrrad" -Objekte zu erstellen und die Eigenschaftswerte "Name" und "Preis" jedes Fahrrads einzugeben.

Jetzt habe ich diese Funktion in mehreren Softwareprodukten gesehen, also muss es ein bekanntes Konzept sein. Mein Problem begann, als ich mich hinsetzte und versuchte, ein DB-Schema zu erstellen, um diese Datenstruktur zu unterstützen, weil ich die Eigenschaftswerte mit den entsprechenden Spaltentypen speichern möchte. Ie. Ein numerischer Eigenschaftswert wird beispielsweise als INT in der Datenbank gespeichert, und ein Texteigenschaftswert wird als VARCHAR gespeichert.

Zuerst muss ich eine Tabelle, die alle meine Objektdefinitionen halten:

Table obj_defs 

id | name  | 
---------------- 
1 | "Bicycle" | 
2 | "Book" | 

Dann brauche ich einen Tisch zum Halten, welche Art von Eigenschaften jeder Objektdefinition haben sollte:

Table prop_defs 

id | obj_def_id | name  | type | 
------------------------------------ 
1 |   1 | "Size" | ? | 
2 |   1 | "Name" | ? | 
3 |   1 | "Price" | ? | 
4 |   2 | "Title" | ? | 
5 |   2 | "Author" | ? | 
6 |   2 | "ISBN" | ? | 

I würde auch eine Tabelle, die jedes Objekt enthält:

Table objects 

id | created | updated | 
------------------------------ 
1 | 2011-05-14 | 2011-06-15 | 
2 | 2011-05-14 | 2011-06-15 | 
3 | 2011-05-14 | 2011-06-15 | 

Schließlich brauche ich eine Tabelle, die wi ll die tatsächlichen Eigenschaftswerte der einzelnen Objekte halten, und eine Lösung ist für diese Tabelle eine Spalte für jeden möglichen Wert Typ aufweisen, wie dies:

Table prop_vals 

id | prop_def_id | object_id | numeric | textual | boolean | 
------------------------------------------------------------ 
1 |   1 |   1 |  27 |   |   | 
2 |   2 |   1 |   | "Trek" |   | 
3 |   3 |   1 | 1249 |   |   | 
4 |   1 |   2 |  26 |   |   | 
5 |   2 |   2 |   | "GT" |   | 
6 |   3 |   2 |  159 |   |   | 
7 |   4 |   3 |   | "It" |   | 
8 |   5 |   3 |   | "King" |   | 
9 |   6 |   4 |  9 |   |   | 

Wenn ich dieses Schema implementiert, was wäre die „Art“ Spalte der Tabelle prop_defs halten? Ganzzahlen, die jeweils einem Spaltennamen zugeordnet sind, varchars, die einfach den Spaltennamen enthalten? Irgendwelche anderen Möglichkeiten? Würde mir eine gespeicherte Prozedur irgendwie helfen? Und wie würde die SQL zum Abrufen der "name" -Eigenschaft von Objekt 2 aussehen?

Antwort

28

Sie implementieren etwas namens Entity-Attribut-Value-Modell .

Viele Leute werden sagen, es ist eine schlechte Idee (normalerweise bin ich einer von denen), weil die Antwort auf Ihre letzte Frage, "Was wäre der SQL zum Holen ..." tendenziell "dick haarig und böse, und schlimmer werden. "

Diese Kritiken neigen dazu, zu halten, sobald Sie Benutzern das Verschachteln von Objekten innerhalb anderer Objekte erlauben. Wenn Sie dies nicht zulassen, bleibt die Situation überschaubar.

Für Ihre erste Frage, "Was würde die" Typ "Spalte der Tabelle prop_defs halten", alles wird einfacher, wenn Sie eine Tabelle von Typen und Beschreibungen haben, die {"numeric", "Any Number"} enthält, {"textual", "String"} usw. Der erste Wert ist der Primärschlüssel. Dann in prop_defs Ihre Spalte "Typ" ist ein Fremdschlüssel für diese Tabelle und enthält Werte "numerisch", "textuell", etc. Einige sagen Ihnen falsch, immer Integer-Schlüssel verwenden, weil sie schneller JOIN, aber wenn Sie die Werte verwenden " Numerische "," textuelle "usw. Sie müssen nicht beitreten und der schnellste JOIN ist derjenige, den Sie nicht tun.

Die Abfrage einen einzelnen Wert eine CASE-Anweisung wird greifen:

SELECT case when pd.type = "numeric" then pv.numeric 
      when pd.type = "textual" then pv.textual 
      when pd.type = "boolean" then pv.boolean 
    from prov_vals pv 
    JOIN prop_defs pd ON pv.prop_def_id = pv.id 
WHERE pv.object_id = 2 
    AND pd.name = "Name" 
+0

Ausgezeichnete Antwort! Vielen Dank :) –

+2

Was wäre dann eine bessere Lösung für den Fall, dass EAV etwas ist, das zu vermeiden ist, wenn die Notwendigkeit, Objekte zu verschachteln, sich darstellt? – ChrisR

+0

Jetzt mit NoSQL-Lösungen wie MongoDB können EAVs schließlich sterben. –

4

Sie akzeptieren müssen, dass relationale Datenbanken bei der Bereitstellung dieser Art von Funktionalität nicht gut sind. Sie können es schaffen, sind aber nicht gut darin. (Ich hoffe, ich liege falsch). Relationale Datenbanken eignen sich besser für definierte Schnittstellen, nicht für die Änderung von Schnittstellen.

--EAV-Tabellen geben dynamische Felder an, sind aber leistungsschwach. Saugt beim Indexieren. Und es ist komplex, abzufragen. Es wird in vielen Situationen erledigt, kann aber an großen Tischen auseinanderfallen, wenn viele Benutzer das System treffen.

- "Reguläre" Tabellen mit mehreren Platzhalterspalten sind OK für die Leistung, aber Sie erhalten nicht beschreibende Spaltennamen und sind in der Anzahl der Spalten beschränkt, die Sie hinzufügen können. Außerdem unterstützt es keine Untertypentrennung.

--Typischerweise erstellen/ändern Sie Tabellen zur Entwicklungszeit, nicht zur Laufzeit. Sollten wir wirklich diskriminieren, die Datenbank zur Laufzeit zu modifizieren? vielleicht, vielleicht nicht. Wenn Sie zur Laufzeit neue Tabellen, Fremdschlüssel und Spalten erstellen, können Sie echte dynamische Objekte erstellen und gleichzeitig die Leistungsvorteile von "normalen" Tabellen nutzen. Sie müssten jedoch das Schema der Datenbank abfragen und dann dynamisch alle Ihre Abfragen generieren. Das wäre scheiße. Es würde das Konzept der Tabellen als Schnittstelle völlig durchbrechen.

Verwandte Themen