Penso di non essere il solo ormai così abituato ad usare Entity Framework e LINQ da dimenticarmi i principi fondamentali tra su cui si basa Entity Framework finché non ci sbatto il muso…. Come oggi
Sto sviluppando la classica applicazioni di scambio dati tra sistemi legacy che fa un uso (ovviamente) importate dell’accessoacesso ai dati. Per cui cosa c’è di più comodo che un bel “reverse engineering” del database legacy per poi poterci operare con LINQ?
Tutto filava per il meglio con mia grande soddisfazione finché non si è presentato il caso di dover chiamare un applicativo esterno che era preposto a fare delle modifiche allo stesso database ma la cui logica era cablata nell’eseguibile e quindi “doveva essere usata così com’era”.
Vi riporto la parte di codice “incriminata”. Il programma reale è (ovviamente) un po’ più complesso e la logica è distribuita su più funzioni (altrimenti il problema mi sarebbe saltato subito all’occhio) ma rende l’idea del “pitfall” in cui si può cadere usando Entity Framework (o un qualsiasi altro ORM) come usiamo (o usavamo) ADO.NET.
N.d.R. “ShellandWait” è una funzione che si preoccupa di lanciare un programma con un parametro ed attenderne la chiusura e…. scusate la sintassi VB
Using ctx = provider.GetDataContext()
Dim ordini = From p In ctx.PortafoglioOrdini
Where p.Ordine = ordine
Select p
If ordini IsNot Nothing Then
For Each ordine In ordini
Dim res = ShellandWait(programmaEsterno, ordine.Riga)
Next
End If
Dim ordineModificato = (From p In ctx.PortafoglioOrdini
Where p.Ordine = ordine
Select p).FirstOrDefault()
Return (ordineModificato IsNot Nothing AndAlso ordineModificato.Stato = "X")
End Using
Diciamo (sempre per semplificare) che tra le varie cose che fa il programma esterno una di quelle è cambiare una colonna della tabella PortafoglioOrdini e io uso questa modifica per verificare che il programma abbia girato correttamente.
Ma il controllo mi tornava sempre false, benché la verifica sul database rendesse evidente che tutto funzionasse al meglio.
Quello che mi ero dimenticato è che il DbContext di Entity Framework implementa i pattern della Unit Of Work e Identity Map per cui una volta letti i dati non li rilegge più dal DB poiché, correttamente in quasi tutti i casi, ritiene di avere conoscenza dello stato letto e di tutte le modifiche apportate al dato che siano state persistite o meno.
Capito il problema (e per una volta senza ricorrere a Stack Overflow ) ho risolto facilmente il problema dividendo il singolo DbContext in due differenti, uno prima e uno dopo la chiamata al programma esterno.