Strutturare un'applicazione reale con Entity Framework

Marco De Sanctis

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

Commenti

Per inserire un commento, devi avere un account.

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



Segnala su: Facebook MSDN Social Twitter Segnalo Wikio Diggita Technorati Stumbleupon Google Yahoo FriendFeed Delicious Furl

TUTORIALS
TOP TEN ARTICOLI
ARTICOLI VIA E-EMAIL

Iscriviti alla nostra newsletter nuoviarticoli per ricevere via e-mail le notifiche!

MEDIA
IN EVIDENZA
MISC