Domanda

Ho uno scenario che non è facile da spiegare, ma sono sicuro che sia un problema molto comune. Farò del mio meglio per illustrare il problema.

Diciamo che abbiamo un'applicazione Survey che ci consente di creare sondaggi. Ogni sondaggio ha una propria struttura (contiene domande, le domande vengono raggruppate e ordinate, ecc.). Tali sondaggi sono gestiti da un amministratore e indicati come modelli di sondaggi principali. Ora l'utente può selezionare uno di quei sondaggi principali, effettuare alcune personalizzazioni e condurre il sondaggio su alcune persone.

Quindi, fondamentalmente, abbiamo sondaggi che condividono tutti la stessa struttura (raccolte, proprietà, ecc.) ma i dati possono essere diversi.

Come modellare il DB?

La mia idea sarebbe quella di memorizzare tutto in una tabella e creare una colonna che separa i modelli da quelli condotti.

tbl_Survey (id, name, conducted_on)

Come modelli le tue classi?

La mia idea sarebbe:

Survey {
  Name
  Questions
}

ConductedSurvey : Survey {
  //gets the master according to the name
  GetMaster()
}

Importante: un sondaggio ha molte relazioni con altre classi. Se decidiamo di sottoclassare. Dovrebbero essere tutti sottoclassati (perché dovremmo copiare i dati dal master per ogni oggetto)?

È stato utile?

Soluzione

  

Quindi, fondamentalmente, abbiamo sondaggi che condividono tutti la stessa struttura (raccolte, proprietà, ecc.) ma i dati possono essere diversi .... La mia idea sarebbe quella di archiviare tutto in una tabella e creare una colonna che separa i modelli da condotte.

Ok, quello di cui stai parlando è un prototipo. Il " template " il sondaggio è un prototipo. Chiaramente, se un prototipo ha esattamente la stessa struttura di un'istanza basata sul prototipo, se sarebbe sciocco e dispendioso creare tabelle completamente diverse per la stessa struttura, tanto più quando ti rendi conto che ciò significa un cambiamento in quella struttura deve rispecchiarsi in entrambi i set.

Aggiungerei una colonna per distinguere un prototipo / modello da un sondaggio condotto? No, probabilmente no. Invece aggiungerei un'altra tabella, con una relazione uno a uno con la tabella di rilevamento radice. In questa tabella, aggiungerei un po 'di metadati che distinguono un prototipo da un non prototipo.

Per tre motivi: 1) in qualsiasi sistema ragionevole, i prototipi saranno una piccola minoranza di sondaggi totali. 2) Vorrei spesso elencare tutti i prototipi, ad es. una "creazione nuova procedura guidata sondaggio" che elenca una scelta di protoipi su cui basare il nuovo sondaggio. E 3) per conservare quel po 'di dati extra:

create table survey_prototype (
    id int not null primary key,
    survey_id references survey(id) -- the regular survey table
    wizard_description varchar(80)
    . . . .
);

Ora, immagino che anche il sondaggio abbia una descrizione, ma che per un prototipo, quella descrizione sia qualcosa di simile a "SOSTITUISCI QUESTA È LA DESCRIZIONE CHE L'UTENTE VEDERÀ". ma quella procedura guidata_descrizione è qualcosa del tipo "Un prototipo di sondaggio politico".

Ora, poiché qualsiasi ricerca di un prototipo / modello non ha alcuna possibilità di restituire un sondaggio condotto (dal momento che nessun sondaggio condotto si unisce a survey_prototype), getMaster appare (concettualmente, presumibilmente usi un ORM) in questo modo:

ConductedSurvey : Survey {
  //gets the master according to the name
  GetMaster() { "select * from survey_prototype join survey..."
}
  

Importante: un sondaggio ha molte relazioni con altre classi. Se decidiamo di sottoclassare. Dovrebbero essere tutti sottoclassati (perché dovremmo copiare i dati dal master per ogni oggetto)?

Hai ragione: per qualsiasi prototipo che recuperi attraverso il tuo ORM, dovrai copiarlo in profondità per salvare un nuovo sondaggio anziché sovrascrivere il prototipo. Dato che devi comunque eseguire la copia in profondità, nella copia in profondità puoi invece copiare la classe base utilizzata dal prototipo e creare una sottoclasse.

Ovviamente dovrai prendere quella decisione ad ogni livello della gerarchia; sarebbe bello incapsulare ogni politica di trasformazione per una trasformazione di copia profonda in una classe. Il modello visitatore lo farà, poiché ha una funzione visit sovraccarica per classe (base) dei tuoi tipi: quindi (almeno) visitSurvey , visitQuestion , visitAnswer .

Dal momento che avrai a che fare con un albero (radicato al sondaggio, con domande dei bambini e risposte dei nipoti, cioè Pattern composito), ti suggerisco di usare il Pattern Visitatore nella tua copia / trasformatore. Poiché le tue lezioni sono relativamente stabili, il visitatore funzionerà bene. E ti consente di avere più visitatori concreti diversi, uno per ogni tipo di trasformazione (e quando arriva il momento di visualizzare o segnare un sondaggio, puoi anche scrivere un visitatore per quello - così avrai quella funzionalità quasi " gratuitamente " una volta impostato il modello visitatore).

Per gestire la sottoclasse nel database, è possibile utilizzare uno qualsiasi dei modelli di nibernazione comuni per questo; in questo modo, una volta che hai visitato e trasformato, avrai un nuovo albero di rilevamento non prototipo che può essere salvato nel database 'automagicamente per nhibernate.

Quindi, per riassumere: tabella survey_prototype, ottenere un prototipo, nhibernate recupererà l'intero albero quando chiedi la radice su survey_prototype, visita quell'albero con un trasformatore di copia profonda che restituisce la radice copiata, lascia che l'utente scriva su quello , salva la radice copiata e lascia che nhibernate salvi in ??modo ricorsivo ogni nodo dell'albero. Quando l'utente deve vedere il sondaggio non prototipo, estrarre la radice dal sondaggio con nibernazione, utilizzare il visitatore display per visualizzarlo, ecc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top