Rollback con linq

martedì 06 novembre 2012 - 10.28
Tag Elenco Tags  C#  |  .NET 3.5  |  Windows 7  |  Visual Studio 2008  |  SQL Server 2008 R2

hydra Profilo | Junior Member

Buongiorno a tutti, non so bene se questo sia un problema legato al linguaggio, al FW o un problema di database, per cui se questa non è la sezione più indicata perdonatemi.
Veniamo al dunque: in una applicazione sto utilizzando LINQ to SQL per gestire un database di piccole dimensioni (circa 5 tabelle con una decina di campi ciascuna). Mi sono creato dei vari metodi per poter gestire gli inserimenti, le modifiche e tutte le cose che mi servono sulle varie tabelle. Siccome l'applicazione non è basata sul database (deve fare tutt'altro) ma utilizza il database per salvare parametri e log, utilizzo il metodo SubmitChanges() ogni volta che inserisco/modifico una tabella (non si dovrebbe fare ma appunto ogni operazione è singola, non devo inserire migliaia di dati alla volta).
In ogni metodo gestisco il tutto con un try-catch in modo che se c'è qualche errore venga notificato e gestito, quello che ho notato però è che, sebbene il metodo SubmitChanges() generi un'eccezione che viene gestita, non esegue il rollback e quando vado a fare una qualsiasi altra operazione sul database (dopo l'eccezione), l'errore rimane e mi compare ogni volta, anche se ad esempio l'operazione è completamente diversa (me ne sono accorto perchè analizzando i messaggi ho notato che l'errore che mi compare non ha niente a che vedere con l'operazione che sta eseguendo) e anche se l'operazione va a buon fine. Ora, a parte il fatto che sto analizzando il codice per capire perchè in certi casi mi genera un errore, sapete dirmi se esiste un modo per eseguire il rollback del submit?
Cercando in rete ho provato a usare il TransactionScope come consigliato in questo link: http://stackoverflow.com/questions/1490731/rollback-with-linq-to-sql ma non mi funziona: se mantengo la struttura con il try-catch mi esegue le istruzioni del catch quando genera l'eccezione e non cambia niente, se non uso il try-catch mi si blocca l'esecuzione perchè ha generato un'eccezione. Mi sapete indicare una strada? Tenete conto anche che stiamo parlando di un progetto finito che è stato consegnato circa un anno fa, quindi non posso stravolgere completamente il codice. Grazie mille a chiunque mi aiuti a venire a capo di questo problema.

algraps Profilo | Junior Member

Ciao,
guarda questo link, soprattutto la risposta al post.
http://stackoverflow.com/questions/542525/transactionscope-vs-transaction-in-linq-to-sql

Fammi sapere.
Ciao
A.G.

hydra Profilo | Junior Member

Grazie della risposta. Da quello che ho capito già il metodo SubmitChanges dovrebbe arrangiarsi. In realtà da quello che ho visto non lo fa. Ti faccio un esempio: in una tabella ho messo dei campi decimal con due cifre decimali, mi sono accorto però che in alcuni casi recupero dei valori con più cifre e non li tronco, quindi mi genera un errore. Il successivo submit, anche se tutti i dati sono corretti, mi torna fuori l'errore (es Il valore "870287.38200" del parametro non è compreso nell'intervallo). Mi sono accorto di questa cosa perchè stampo un messaggio che indica il metodo chiamante e analizzando il codice quel metodo non va a scrivere nessun valore decimale, scrive solamente interi e stringhe, quindi mi pare di capire che sia "rimasto in memoria" l'errore del commit precedente, ossia pare che l'operazione precedente, non essendo stata eseguita correttamente, mi rigeneri l'errore perchè è ancora in attesa.
Se è veramente come dice il link che mi hai postato non lo dovrei vedere l'errore, o sbaglio?

hydra Profilo | Junior Member

Mi è venuta in mente un'altra cosa. Ho creato una classe che mi gestisce tutta la comunicazione con il database, dentro questa classe ho una variabile globale (internal) che istanzio nel costruttore passando come parametro la stringa di connessione. Il punto è che io in ogni punto dove vado a usare il database utilizzo quest'istanza, che è una sola per tutta l'applicazione. Secondo voi è giusto utilizzare una istanza singola oppure mi conviene in ogni metodo dichiarare un'istanza locale, istanziarla, usarla e cestinarla? Ho fatto una prova, provando a inserire un record la cui PK è già presente nel database: prima mi generava l'errore che rimaneva in tutte le successive chiamate, con l'istanza locale l'errore viene visualizzato solamente in quel metodo. Tra l'altro ho visto che il tipo di eccezione sollevata è diversa. Il mio dubbio ora è, posso tranquillamente creare le varie istanze in tutti i metodi che richiamano il database oppure è meglio tenere l'istanza globale?

algraps Profilo | Junior Member

Ciao,
scusa la mia tarda risposta ma ieri sono stato un po' incasinto per lavoro.
Ti allego un AbstractTable . Come potrai vedere io svuoto la cache del DataContext dopo ogni operazione. Poi controllo anche il conflictmode. In questo modo mi sono un attimo protetto per i dati che rimangono in cache.

Ciao
Fammi sapere
A.G.

hydra Profilo | Junior Member

Ciao e grazie nuovamente per la risposta.
Dopo aver fatto alcune prove ho appunto verificato che usare un'istanza globale di connessione al database mi esponeva a quel problema, mentre creare un'istanza locale per ogni metodo fa si che quando il metodo termina anche l'istanza viene eliminata e quindi anche gli eventuali errori. Sono quindi riuscito ad arginare il problema dovuto all'errore che si ripresenta. Non so se sia una soluzione elegante o quantomeno corretta. Inoltre ho scovato alcuni punti che mi generavano degli errori, principalmente dovuti al fatto che alcuni dati non erano formattati correttamente prima di essere inseriti. Adesso ho inviato una release al cliente e vediamo se mi dice che cambia qualcosa o meno. Ti ringrazio anche del codice, appena ho un attimo gli do un occhio.
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2017
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5