Salve,
Proseguendo nello sviluppo di un framework aziendale basato su ADO.NET Entity Framework, mi sono imbattuto nel seguente problema:

Ho problemi di concorrenza nella realizzazione di due thread che operano sul medesimo contesto.

Preciso che i due thread operano su entità distinte e scollegate.

l'errore è il seguente:

"Errore del provider sottostante in Open. "
StackTrace: " in System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)\r\n in System.Data.EntityClient.EntityConnection.Open()\r\n in System.Data.Objects.ObjectContext.EnsureConnection()\r\n in System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)\r\n in System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()\r\n in ApplicazioneEsempioTest.UnitTest1.threadWork() in C:\\VSSFilippo\\VisualStudio\\FrameworkFilippo2\\ApplicazioneEsempioTest\\UnitTest1.cs:riga 1380\r\n in System.Threading.ThreadHelper.ThreadStart_Context(Object state)\r\n in System.Threading.ExecutionContext.runTryCode(Object userData)\r\n in System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)\r\n in System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n in System.Threading.ThreadHelper.ThreadStart()"
"

Effettuando delle ricerche nella rete sembra che sia una limitazione della corrente versione di EF.
le risorse correlate sono le seguenti:

- http://blogs.msdn.com/dsimmons/pages/ef-faq-misc.aspx#Section_18
- http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/d244c4d4-9574-419b-b78f-d0a3d11c235d

Qualcuno ha già affrontato tale problema e sa indicarmi una possibile soluzione o un modo di aggirare il problema (escluso l'utilizzo di due contesti separati per i due thread) ?

Grazie.

- Andrea Bianchi -
Site:http://www.bianchiandrea.com
Da documentazione, i membri d'istanza di ObjectContext non sono thread safe. Questo vuol dire che se hai necessità di gestirne l'accesso da due thread differenti, non ti resta che utilizzare dei sistemi di lock per bloccare la risorsa durante l'uso.

A presto,
m.
Grazie per la risposta.

Vorrei sapere nel mio caso pratico come intenderesti implementare la sincronizzazione. E se esiste un modo per realizzarla in automatico senza implementarla manualmente ad ogni dichiarazione del thread.

MIO SCENARIO:

public Entities mEntitiesInCondivisione;

public void threadWork()
{
var k = from o in mEntitiesInCondivisione.E3
select o;

foreach (E3 kk in k)
kk.CampoE3 = "sds";
}

public void threadWork2()
{
var k = from o in mEntitiesInCondivisione2.E4
select o;

foreach (E4 kk in k)
kk.CampoE4 = "dssfdfsa";
}

[TestMethod]
public void Tread()
{
using (Entities context = new Entities())
{
mEntitiesInCondivisione = context;

Thread newThread = new Thread(this.threadWork);
Thread newThread2 = new Thread(this.threadWork3);

newThread.Start();
newThread2.Start();

newThread.Join();
newThread2.Join();
}
}

- Andrea Bianchi -
Site:http://www.bianchiandrea.com
Significa modificare i tuoi metodi threadWork e threadWork2 in
public void threadWork()
{
  lock (syncObject)
  {
    var k = from o in mEntitiesInCondivisione.E3
    select o;

    foreach (E3 kk in k)
    kk.CampoE3 = "sds";
  }
}

dove syncObject è un oggetto qualsiasi condiviso tra i due thread, nel tuo esempio potrebbe essere dichiarato all'interno della classe
private object syncObject = new object();


Il lock garantisce che un solo thread per volta utilizzi l'object context, dato che lo statement lock invocato dal thread numero 2 resta bloccato finchè il thread 1 non è uscito dal blocco. Ovviamente così ti giochi il parallelismo, ma se non è supportato non puoi farci granché.

Ciao,
m.
E' un po un peccato che uno strumento come Entity Framework non gestisca in automatico queste problematiche.

Secondo te ci può essere un modo per mettersi in mezzo e fornire il servizio di sincronizzazione su ogni oggetto che si accede?

Grazie ancora per le dritte.

- Andrea Bianchi -
Site:http://www.bianchiandrea.com
Mah... è invece piuttosto comune e francamente non saprei proprio come realizzare un accesso ai dati thread safe: un thread apre una connessione, esegue una stored proc, recupera un cursore, poi mentre sta leggendo il cursore un altro thread esegue un altro command per un inserimento aprendo una transazione sulla *stessa* connessione, poi la chiude...

Capita la problematica?

Se vuoi il mio parere, usa un object context per thread, è questa la modalità di lavoro supportata e distaccarsene vuol dire solo farsi del male.

Ciao,
m.

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.