2011-01-16 15 views
17

Sto lavorando a un editor che consente agli utenti di creare definizioni di "oggetto" in tempo reale. Una definizione può contenere zero o più proprietà. Una proprietà ha un nome un tipo. Una volta creata una definizione, un utente può creare un oggetto di quella definizione e impostare i valori della proprietà di tale oggetto.Schema per il supporto delle proprietà dinamiche

Quindi, con un clic del mouse, l'utente dovrebbe es. essere in grado di creare una nuova definizione chiamata "Bicicletta" e aggiungere la proprietà "Dimensioni" del tipo "Numerico". Quindi un'altra proprietà denominata "Nome" di tipo "Testo" e quindi un'altra proprietà denominata "Prezzo" di tipo "Numerico". Una volta fatto, l'utente dovrebbe essere in grado di creare un paio di oggetti "Bicicletta" e inserire i valori delle proprietà "Nome" e "Prezzo" di ogni bicicletta.

Ora, ho visto questa funzione in diversi prodotti software, quindi deve essere un concetto ben noto. Il mio problema è iniziato quando mi sono seduto e ho cercato di creare uno schema DB per supportare questa struttura dati, perché voglio che i valori delle proprietà siano archiviati usando i tipi di colonna appropriati. Vale a dire. un valore di proprietà numerico viene memorizzato come, ad esempio, un INT nel database e un valore di proprietà testuale viene memorizzato come VARCHAR.

In primo luogo, ho bisogno di una tabella che conterrà tutte le mie definizioni di oggetto:

Table obj_defs 

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

Poi ho bisogno di un tavolo per lo svolgimento di che tipo di proprietà ogni definizione di oggetto deve avere:

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 Avrebbe anche bisogno di una tabella che contiene ogni oggetto:

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 | 

Infine, ho bisogno di un tavolo che wi ll contenere i valori delle proprietà reali di ogni oggetto, e una soluzione è per questa tabella abbia una colonna per ogni possibile tipo di valore, come questo:

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 |   |   | 

Se ho implementato questo schema, quale sarebbe il "tipo" colonna della tabella prop_defs premuto? Integers che si associano a un nome di colonna, varchars che semplicemente contengono il nome della colonna? Altre possibilità? Una procedura memorizzata potrebbe aiutarmi qui in qualche modo? E come apparirebbe l'SQL per il recupero della proprietà "nome" dell'oggetto 2?

risposta

28

Si sta implementando qualcosa chiamato modello Entity-Attribute-Value http://en.wikipedia.org/wiki/Entity-attribute-value_model.

Un sacco di gente dirà che è una cattiva idea (di solito io sono uno di quelli) perché la risposta alla tua ultima domanda, "Cosa sarebbe l'SQL per il recupero ..." tende ad essere "spessa pelosa e cattiva, e peggio ancora. "

Queste critiche tendono a rimanere valide una volta che si consente agli utenti di iniziare a nidificare oggetti all'interno di altri oggetti, se non lo consentono, la situazione rimarrà gestibile.

Per la prima domanda, "quale sarebbe la colonna" tipo "della tabella prop_defs", tutto sarà più semplice se si dispone di una tabella di tipi e descrizioni che contiene {"numerico", "Qualsiasi numero"}, {"testuale", "Stringa"}, ecc. Il primo valore è la chiave primaria. Poi in prop_defs la tua colonna "tipo" è una chiave estranea a quella tabella e contiene valori "numerico", "testuale", ecc. Alcuni ti diranno in modo errato di usare sempre chiavi intere perché si uniscono più velocemente, ma se usi i valori " numerico "," testuale "ecc. non è necessario ISCRIVERSI allo e il JOIN più veloce è quello che non si fa.

La query di afferrare un singolo valore avrà una dichiarazione CASE:

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

Ottima risposta! Grazie mille :) –

+2

Quale sarebbe quindi una soluzione migliore nel caso in cui l'EAV sia qualcosa da evitare quando si presenta la necessità di nidificare gli oggetti? – ChrisR

+0

Ora con soluzioni NoSQL come MongoDB, gli EAV possono finalmente morire. –

4

è necessario accettare che i database relazionali non sono bravi a fornire questo tipo di funzionalità. Possono fornirlo, ma non sono bravi a farlo. (Spero di sbagliarmi). I database relazionali si prestano meglio alle interfacce definite, non cambiando le interfacce.

- Le tabelle EAV forniscono campi dinamici ma fanno schifo sulle prestazioni. Succhia all'indicizzazione Ed è complesso interrogare. Ottiene il lavoro svolto in molte situazioni, ma può cadere a pezzi su grandi tavoli con un sacco di utenti che colpiscono il sistema.

- Le tabelle "normali" con diverse colonne di segnaposto sono OK per le prestazioni, ma i nomi delle colonne non descrittivi sono limitati e il numero di colonne che è possibile "aggiungere" è limitato. Inoltre non supporta la separazione sotto-tipo.

- In genere si creano/modificano tabelle in fase di sviluppo, non in fase di esecuzione. Dovremmo davvero discriminare la modifica del database in fase di esecuzione? forse sì forse no. La creazione di nuove tabelle, chiavi esterne e colonne in fase di esecuzione può consentire la realizzazione di oggetti dinamici reali, garantendo al tempo stesso i vantaggi in termini di prestazioni delle tabelle "normali". Ma dovresti interrogare lo schema del database, quindi generare dinamicamente tutte le tue query. Questo farebbe schifo. Interromperebbe totalmente il concetto di tabelle come interfaccia.

Problemi correlati