in

dotNet Umbria

Il primo User Group in Umbria sul mondo .Net

Andrea Cruciani' blog

parlando di .Net: i miei libri, architettura, il Web, le applicazioni mobile, Wpf, MicroFramework...

Linq to SQL InheritanceMapping

L'altro giorno mi sono ritrovato a fare una chiacchierata con Simone, grande supporter di NHibernate, su alcune delle features di Linq e ci siamo trovati concordi nel dire che l'Inheritance mapping è una tra le più interessanti per i nostri porgetti reali.
Per chi non avesse ancora visto Linq to Sql và fatta una piccola premessa: il modo più immediato ed intuitivo di mappare le tabelle del nostro db (Linq to Sql al momento supporta solo Sql Server) è quello di aggiungere un nuovo item al nostro progetto di tipo "Linq to Sql classes", di creare una connessione in Server Explorer al db che vogliamo utilizzare e tramite drag&drop trascinare le tabelle che ci interessano. Vediamo il risultato in figura:

 

Questo tipo di mapping prevede l'utilizzo degli attributi per legare le proprietà delle entità generate con i campi presenti nelle tabelle del db. Alternativamente è possibile utilizzare un mapping esterno su files Xml che però non ci interessa per l'esempio corrente.

L'idea è quella di avere una classe per rappresentare un generico item di una rubrica (chiamato fantasiosamente Rubrica) e di andare a specializzarlo in classi specifiche per la rurbrica dei fornitori, clienti e magari delle aziende. VS2008 ci genera una classe Rurbica che mappa in modo semplice la nostra tabella. Ereditiamo qundi questo tipo nelle classi che rappresentano Clienti,Fornitori ed Aziende:

 

All'interno della tabella esiste un campo denominato ContactType (tinyint ovvero byte in .Net) che ho stabilito mi specificherà il tipo di contatto. Ora voglio che Linq to Sql mi restituisca l'entità giusta a seconda del valore del ContactType, per fare questo devo agire in due step sulla classe Rubrica generatami da VS2008.

Sulla proprietà che mi mappa il ContentType imposto l'attributo IsDiscriminator a true per l'attributo Column. In questo modo specifico che sarà questa la proprietà che definirà il tipo da generare.

[Column(Storage = "_ContactType", DbType = "TinyInt NOT NULL", IsDiscriminator = true)]
public byte ContactType

Successivamente applico i seguenti attributi al tipo Rubrica:

[Table(Name = "dbo.Rubrica")]
[
InheritanceMapping(Code = TipoContatto.Rubrica, Type = typeof(Rubrica), IsDefault = true)]
[
InheritanceMapping(Code = TipoContatto.Cliente, Type = typeof(Cliente))]
[
InheritanceMapping(Code = TipoContatto.Fornitore, Type = typeof(Fornitore))]
[
InheritanceMapping(Code = TipoContatto.Azienda, Type = typeof(Azienda))]
public partial class Rubrica

L'attributo InheritanceMapping determina quale sia il valore del campo per cui mi verrà generato uno specifico tipo. Nel primo attributo abbiamo anche impostato quale sia il valore di default (nel caso che il ContentType no nricadesse in nessuno dei valori esplicitati).

Avrete notato che a fronte di un ContentType numerico sto utilizzando un enum per specificare i vari casi, la scelta è stata fatta solo per aumentare la leggibilità , è bastato definire l'enum TipoContatto come segue:

public enum TipoContatto : byte
{
     Rubrica = 0,
     Cliente = 1,
     Fornitore = 2,
     Azienda = 3,
}

Fatto questo il motore di Linq to Sql interpreterà il valore del parametro discriminante e restituirà gli oggetti corretti. All'interno di ciascun oggetto potremo apportare le modifiche volute e dei metodi specifici per ciascuna entità.

Nell'esempio allegato trovate un'implementazione che utilizza un campo CodiceUnivoco per inserire, a seconda del caso, il codice fiscale o la partita iva. Avrei potuto allo stesso modo inseire dei validatori differenti per i due casi. Nello zip trovate anche la query per generare la tabella del database se volete fare una prova completa.

Only published comments... Feb 22 2008, 10:51 AM by Andrea Cruciani
Filed under:

Comments

 

belius said:

Hey, ma lo sai che che con un post hai espresso 3 concetti fondamentali di LINQ:

1. Quanto ti aiuta a creare il design di un dominio pulito

2. Quanto è semplice e veloce integrarlo ed estenderlo

3. Che potenza ti da la sintassi dichiarativa

La cosa magnifica di LINQ (e di altri ORM) è proprio questo.....grande Andrea

P.S. chiacchierata e amatriciana.....quale miglior modo per parlare di informatica?

February 22, 2008 1:39 PM
 

Andrea Cruciani said:

Direi che meglio c'è solo il raviolo panna e tartufo, propongo una cadenza fissa all'appuntamento :-)

February 22, 2008 3:11 PM

About Andrea Cruciani

Sviluppatore da sempre ha iniziato a lavorare in .Net sin dalla prima versione. Mi interesso di problemi di architetturali, di applicativi web e dispositivi Mobile. Recentemente con l'avvento di WinFx ho iniziato a lavorare con Wpf e Wcf. Assieme a Paolo abbiamo creato TeamDev.
dotNet Umbria 2007-2008
Powered by Community Server (Commercial Edition), by Telligent Systems