Strutturare un'applicazione reale con Entity Framework
di Marco De Sanctis, in LINQ, 24 marzo 2009
4 pagine in totale: <<Indietro 1 [2] 3 4 Avanti >>
Detach e Attach di una Entity
Allo scopo è presente nell'ObjectContext il metodo Detach, che sostanzialmente consente di riportare una entity persitent in stato Detached. Successivamente, essa potrà essere aggangiata ad un nuovo object context invocando il metodo Attach.
Customer myCustomer; using (ObjectContext firstContext = new ObjectContext()) { myCustomer = ... // fetch del customer firstContext.Detach(myCustomer); } // qui myCustomer è DETACHED using (ObjectContext anotherContext = new ObjectContext()) { anotherContext.Attach(myCustomer); // qui myCustomer è nuovamente PERSISTENT }
L'operazione di Detach deve obbligatoriamente avvenire prima che venga persa la reference al firstContext citato nello snippet precedente; in caso contrario, infatti, il successivo Attach fallisce sollevando un'eccezione che indica che la entity è agganciata ad un'altro ObjectStateManager. Purtroppo in Entity Framework effettuare il Detach non può sicuramente essere catalogata tra le operazioni più "comode":
- non si tratta di un'operazione transitiva e nel caso si voglia effettuare il detach di un grafo complesso, tutte le entity devono essere rimosse puntalmente; in altre parole, insomma, se si vuole rimuovere un customer con l'elenco dei suoi contacts, sarà necessario invocare il metodo detach una volta per ognuno di questi oggetti.
- eventuali navigation properties, come ad es. la collection Customer.Contacts, vengono svuotate a seguito dell'operazione di detach e dovranno pertanto essere ricostruite manualmente.
Una ben più comoda alternativa, per esempio, può essere quella di configurare un object context, e in particolare uno o più entity set, disabilitando il tracking delle modifiche tramite la proprietà MergeOption:
Customer myCustomer; using (ObjectContext firstContext = new ObjectContext()) { firstContext.CustomerSet.MergeOption = MergeOption.NoTracking; myCustomer = ... // fetch del customer } using (ObjectContext anotherContext = new ObjectContext()) { // è possibile effettuare l'attach senza aver // preventivamente invocato un detach anotherContext.Attach(myCustomer); // ... }
Il risultato dello snippet precedente è che l'oggetto non diviene mai persistente all'interno di "firstContext" e pertanto l'attach ad "anotherContext" è da subito lecito.
Volendo sfruttare queste nuove nozioni nella pagina ipotizzata in precedenza, allora, ne consegue che è effettivamente possibile memorizzare il customer in sessione, in modo che esso sopravviva per tutta la durata della business transaction:
private Customer currentCustomer { get { return this.Session["customer"] as Customer; } set { this.Session["customer"] = value; } } private void loadCustomer(int customerId) { using (ObjectContext context = new ObjectContext()) { context.CustomerSet.MergeOption = MergeOption.NoTracking; currentCustomer = (from c in context.CustomerSet where c.Id == customerId select c).First(); this.txtId.Text = customer.Id.ToString(); this.txtName.Text = customer.Name; // e così via... } }
Al salvataggio, sarà sufficiente effettuarne l'attach prima di procedere all'aggiornamento:
protected void btnSave_Click(object sender, EventArgs e) { using (ObjectContext context = new ObjectContext()) { context.Attach(currentCustomer); customer.Name = txtName.Text; customer.Address = txtAddress.Text; // e così via... context.SaveChanges(); } }
Gestione di modifiche offline
Un approccio di questo tipo risolve sicuramente la problematica della gestione manuale della concorrenza, illustrata un paio di paragrafi fa, ma lascia aperti molti dubbi relativi alla gestione di grafi complessi, che in pratica è proprio la casistica che solitamente fa optare per il mantenimento della entity in sessione. In tutti gli esempi precedenti abbiamo apportato le modifiche alla entity in un particolare istante temporale, ossia dopo che questa fosse stata agganciata al contesto di persistenza che ne avrebbe poi decretato il salvataggio. In generale, ciò non è sempre possibile: si pensi ad esempio alla gestione di una relazione master-detail, che magari dura svariati postback, durante i quali l'utente aggiunge, modifica o elimina righe di dettaglio (ad es. i contatti di un customer), provocando di fatto delle variazioni sulla entity in sessione in una fase in cui questa è in stato detached. Questo scenario cozza decisamente contro una caratteristica dell'operazione di Attach che fino ad ora non è stata menzionata, ossia il fatto che essa renda sì la entity persistente, ma ne imposti lo stato ad Unchanged; è il motivo per cui, ad esempio, la semplice aggiunta di un contatto al di fuori del contesto di persistenza non produca alcuna query di INSERT al salvataggio delle modifiche:

L'ObjectContext espone un metodo ApplyPropertyChanges che, senza entrare troppo nel dettaglio, serve proprio a gestire modifiche offline, ma, analogamente al detach, presenta il problema di non prendere in considerazione le navigation property e, quindi, eventuali oggetti collegati. Il risultato è che si rende necessaria per lo sviluppatore una certa mole di "lavoro manuale", volta a ricostruire il corretto stato di modifica degli oggetti, che all'aumentare della complessità del grafo può diventare inaccettabile. In questi casi, allora, l'unica alternativa praticabile è quella di fare in modo che anche l'object context persista per tutta la durata della transazione di business, eliminando quindi la necessità di qualsivoglia detach e re-attach.
4 pagine in totale: <<Indietro 1 [2] 3 4 Avanti >>
Attenzione: Questo articolo contiene un allegato
Contenuti dell'articolo
Sullo stesso argomento
-
L'accesso ai dati nell'era del cloud computing con Windows Azure
-
Utilizzare Entity SQL per eseguire query in Entity Framework
-
Oltre il database, da Bing a Twitter: i provider per LINQ per ogni esigenza
-
Entity Framework ed NHibernate a confronto
-
Ottimizzare le performance di un'applicazione che utilizza Entity Framework
-
Utilizzare le stored procedure con Entity Framework
-
Modificare i dati con Entity Framework
-
Introduzione a LINQ to XML
-
Introduzione ad ADO.NET Entity Framework

















Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.