Mapping dell'ereditarietà con Table-Per-Type in Entity Framework

di Marco De Sanctis, in LINQ, Entity Framework,

Nello script #94 abbiamo visto come è possibile effettuare il mapping di una gerarchia di oggetti associandola per intero ad una sola tabella sul database. Questa strategia presenta però alcuni svantaggi:
1) Classi molto eterogenee producono tabelle con un gran numero di colonne le cui righe presentano molteplici valori a NULL
2) non è possibile inserire a livello di database vincoli di not-nullable sulle colonne specifiche di un tipo, nonostante magari a livello di business siano obbligatorie
3) Non è possibile forzare a livello di database (a meno di non usare soluzioni custom come trigger) le foreign key ad un particolare membro della gerarchia, dato che un vincolo di chiave esterna è soddisfatto da qualsiasi elemento della gerarchia stessa.
Un'alternativa, supportata da ADO.NET Entity Framework, è quello di utilizzare una specifica tabella per ogni classe concreta del modello a oggetti. Pertanto, lo stesso modello di dominio dello script #94 può essere persistito su uno schema simile al seguente:

Si noti che:
1) tutte le relazioni sono di tipo 1 a 1, dato che si tratta di vincoli di foreign key tra chiavi primarie (es. Automobili.AutomobileId e Veicoli.Id
2) per questo motivo, solo Veicoli.Id può essere di tipo Identity, mentre per gli altri è necessario poter specificare direttamente un valore
Importando uno schema di questo tipo in un object model, ADO.NET Entity Framework crea per default quattro entity e altrettante associazioni, che devono quindi essere eliminate manualmente e sostituite con le relazioni di ereditarietà; inoltre nelle classi derivate si possono eliminare anche le proprietà generate a partire dalle chiavi delle rispettive tabelle (quindi AutomobileId, CiclomotoreId e FurgoneId), visto che la chiave sarà esclusivamente la proprietà Id della classe base Veicolo:

Infatti, il successivo e ultimo passo è proprio quello di mappare quest?ultima proprietà su ognuna delle chiavi primarie delle singole tabelle, come mostrato in figura per la classe Automobile:

A questo punto ADO.NET Entity Framework possiede tutte le informazioni per persistere correttamente una gerarchia di entity di questo tipo. Infatti, ad esempio, il salvataggio di un nuovo Furgone

using (TestdbEntities context = new TestdbEntities())
{
  Furgone furgone = new Furgone();
  // ...si valorizzano le proprietà...
  context.AddToVeicoli(furgone);
  context.SaveChanges();
}

produce tre query di INSERT sulle distinte tabelle Veicoli, Automobili e Furgoni:

INSERT [dbo].[Veicoli]([Proprietario], [NumeroAssicurazione]) VALUES (@0, @1) 
SELECT [Id] FROM [dbo].[Veicoli] WHERE @@ROWCOUNT > 0 AND [Id] = SCOPE_IDENTITY()

INSERT [dbo].[Automobili]([AutomobileId], [AriaCondizionata], [Servosterzo], 
[NumeroAirbag]) VALUES (@0, @1, @2, @3)

INSERT [dbo].[Furgoni]([FurgoneId], [CapacitàBagagliaio]) VALUES (@0, @1)

In un prossimo script, discuteremo le differenze e le implicazioni delle due strategie di mapping relativamente alla fase di fetch dei dati.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi