Sto preparando la struttura dati di un progetto (in codice ) in un'applicazione ASP .NET Core 2 , con l'aiuto di Entity Framework . Questo rapporto specifico non ho esperienza con: l'utente deve essere in grado di scegliere le malattie con caselle di controllo, e abbiamo scelte simili: tipo di cancro, dieta, ecc.
Ho più di due tabelle come quelle sulla foto, che verranno indirizzate dalla tabella UserKitProperties . Questa tabella dovrebbe funzionare come una tabella di connettori, connettere l'entità utente con altre entità.
userid1 | cancertypeid1
userid2 | dietaryid1
userid1 | cancertypeid2
userid3 | dietaryid1
Come dovrebbe essere specificato nel codice, per supportare questa relazione? Stavo pensando di fare una lezione base e magari riferirmi a quell'id. E questa è la classe del connettore ..
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
// this should be used for cancer type, dietary, etc..
public long PropertyID { get; set; }
/* Instead of using two classes' ids, maybe call the base class' id
[ForeignKey("PropertyID")]
public CancerType CancerTypes { get; set; }
[ForeignKey("PropertyID")]
public Dietary Dietaries { get; set; } */
}
Grazie in anticipo per i tuoi suggerimenti! :)
Invece di pensare prima al layout del database, dovresti pensare a come rappresenterai questa relazione nel codice. Dopo tutto, stai facendo un approccio code-first.
Ci sono fondamentalmente due scelte che puoi scegliere: o il paziente ha più proprietà, una per ogni tipo di proprietà, oppure esiste una sola raccolta per tutte le proprietà:
public class Patient
{
// …
// option 1
public CancerType CancerType { get; set; }
public Dietary Dietary { get; set; }
public OtherProperty OtherProperty { get; set; }
// option 2
public IList<PatientProperty> Properties { get; set; }
}
Entrambe queste opzioni hanno i loro vantaggi e svantaggi. Mentre l'opzione 1 è molto esplicita e impone un singolo valore per ogni tipo, richiede anche di avere una proprietà (di classe) per ogni proprietà (paziente). Quindi, se estendi il modello in un secondo momento, dovrai adattare il modello del paziente.
L'opzione 2 ha il vantaggio di poter semplicemente raccogliere tutto. Quindi puoi semplicemente aggiungere proprietà al tuo paziente senza dover modificare il modello in seguito se introduci nuove proprietà. Inoltre, supporta anche più selezioni per un singolo tipo. Al rovescio della medaglia, non verifica nulla da solo, quindi è necessaria la logica di business per applicare effettivamente le regole.
Passando al database, per l'opzione 2 è ovviamente necessario un link table poiché questa è una relazione molti-a-molti ora. Dal momento che hai solo un collegamento al tipo base PatientProperty
ma in realtà vuoi parlare del tipo concreto, avrai bisogno di un qualche tipo di discriminatore . I discriminatori sono fondamentalmente solo una notazione per memorizzare ulteriormente il tipo di oggetto nel database.
Quando si archiviano dati con ereditarietà, ciò che viene comunemente fatto è "table-per-hierarchy ". Ciò significa che tutti i tipi all'interno della gerarchia del tipo base PatientProperty
condivideranno la stessa tabella. Una colonna discriminatore viene utilizzata per specificare il tipo e le proprietà aggiuntive che alcuni tipi di proprietà potrebbero avere sono implementate con colonne nullable. Questa configurazione funziona immediatamente con Entity Framework ed è descritta in questo capitolo nella documentazione .
L'altro approccio, "table-per-type "non è supportato in EF Core, quindi se si desidera seguire ciò, è necessario implementarlo da soli. Ma nel tuo caso, laddove i tipi di proprietà sono per lo più molto simili, in realtà mi oppongo e li tengo effettivamente nella stessa tabella.
Per l'opzione 1, purché si abbia una sola proprietà di ciascun tipo assegnata al paziente, le cose sono un po 'più semplici. Dal momento che non hai molti a molti lì, non hai davvero bisogno di un tavolo di collegamento. Hai solo bisogno di memorizzare l'id per ogni tipo di proprietà collegata nel modello del paziente, come mostrato nella UML sopra. In questo modo, puoi anche mantenere i tipi di proprietà come tipi separati che non condividono una singola tabella nel database.
Il seguente dovrebbe funzionare:
public class Property
{
public long PropertyId { get; set; }
}
public class CancerType : Property
{
// Your code
}
public class Dietary : Property
{
// Your code
}
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
public long PropertyID { get; set; }
[ForeignKey("PropertyID")]
public Property Property { get; set; }
}
Tuttavia, come menzionato da questo documento MS, l'impostazione di tale ereditarietà utilizzerà una colonna Discriminator speciale nella tabella della classe base, per rappresentare quale tipo specifico è archiviato in una riga.
Personalmente farei ricorso ad avere campi nullable al fine di non aggiungere più complessità. Ciò non impone, tuttavia, che PatientProperties
abbia solo una proprietà, che è un considerevole svantaggio:
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
public long? CancerTypeID { get; set; }
[ForeignKey("CancerTypeID")]
public CancerType CancerType { get; set; }
public long? DietaryID { get; set; }
[ForeignKey("DietaryID")]
public Dietary Dietary { get; set; }
}