Ho già sviluppato un'applicazione con EF6 e MS-SQL Server.
Ovunque nella mia applicazione ho scritto il codice come di seguito dove avevo bisogno di inserire, aggiornare o cancellare i dati dalla tabella:
Codice:
using (DemoEntities objContext = GetDemoEntities())
{
using (TransactionScope objTransaction = new TransactionScope())
{
Demo1(objContext);
Demo2(objContext);
// Commit the changes in the database.
objTransaction.Complete();
}
}
public void Demo1(DemoEntities objContext)
{
Demo1 objDemo1 = new Demo1();
objDemo1.Title = "ABC";
objContext.Demo1.Add(objDemo1);
objContext.SaveChanges();
}
public void Demo2(DemoEntities objContext)
{
Demo2 objDemo2 = new Demo2();
objDemo2.Title = "ABC";
objContext.Demo2.Add(objDemo2);
objContext.SaveChanges();
}
La mia applicazione è in esecuzione su un server e il database è in esecuzione su un altro server in AWS.
La mia applicazione funziona senza intoppi, ma 2-3 volte debolmente ho ricevuto l'errore come il seguente.
System.Data.Entity.Core.EntityException: il provider sottostante non è riuscito su Apri. ---> System.Data.SqlClient.SqlException: si è verificato un errore relativo alla rete o specifico dell'istanza durante la creazione di una connessione a SQL Server. Il server non è stato trovato o non era accessibile. Verificare che il nome dell'istanza sia corretto e che SQL Server sia configurato per consentire le connessioni remote. (provider: Named Pipes Provider, errore: 40 - Impossibile aprire una connessione a SQL Server) ---> System.ComponentModel.Win32Exception: accesso negato
Nella prima richiesta ho ricevuto l'errore sopra riportato e dopo l'immediata richiesta non ho ricevuto alcun errore e la richiesta è andata a buon fine.
Dopo aver fatto un po 'di Google, ho ottenuto il concetto come la Resistenza di connessione che ho implementato nella mia applicazione e funziona e riprovo la query per alcune volte specifiche dopo un periodo specifico.
Ma fallisce nel caso in cui ho usato le mie transazioni personalizzate come nel codice precedente. Getta l'errore in questo modo.
System.InvalidOperationException: la strategia di esecuzione configurata "MYExecutionStrategy" non supporta le transazioni avviate dall'utente. Vedere http://go.microsoft.com/fwlink/?LinkId=309381 per ulteriori informazioni.
Ho configurato la strategia di esecuzione in questo modo:
public class MYExecutionStrategy : DbExecutionStrategy
{
/// <summary>
/// The default retry limit is 5, which means that the total amount of time spent
/// between retries is 26 seconds plus the random factor.
/// </summary>
public MYExecutionStrategy()
{
}
/// <summary>
///
/// </summary>
/// <param name="maxRetryCount"></param>
/// <param name="maxDelay"></param>
public MYExecutionStrategy(int maxRetryCount, TimeSpan maxDelay)
: base(maxRetryCount, maxDelay)
{
}
/// <summary>
///
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
protected override bool ShouldRetryOn(Exception exception)
{
bool bRetry = false;
SqlException objSqlException = exception as SqlException;
if (objSqlException != null)
{
List<int> lstErrorNumbersToRetry = new List<int>()
{
5 // SQL Server is down or not reachable
};
if (objSqlException.Errors.Cast<SqlError>().Any(A => lstErrorNumbersToRetry.Contains(A.Number)))
{
bRetry = true;
}
}
return bRetry;
}
}
E DBConfiguration come questo:
/// <summary>
///
/// </summary>
public class MYConfiguration : DbConfiguration
{
/// <summary>
///
/// </summary>
public MYConfiguration()
{
SetExecutionStrategy("System.Data.SqlClient", () => new MYExecutionStrategy(3, TimeSpan.FromSeconds(1)));
}
}
Domande:
Quindi dopo aver fatto un po 'di RnD e aver letto sul WEB ho trovato la soluzione in questo modo:
var str = MYExecutionStrategy(3, TimeSpan.FromSeconds(1));
str.Execute(() =>
{
using (DemoEntities objContext = GetWDemoEntities ())
{
using (TransactionScope obj = new TransactionScope())
{
Demo1 objDemo1 = new Demo1();
objDemo1.Title = "ABC";
objContext.Demo1.Add(objDemo1);
objContext.SaveChanges(); // First SaveChanges() method called.
Demo2 objDemo2 = new Demo2();
objDemo2.Title = "ABC";
objContext.Demo2.Add(objDemo2);
objContext.SaveChanges();// Second SaveChanges() method called.
obj.Complete();
}
}
}
Con una transazione personalizzata se si verifica un errore di connessione sul secondo SaveChanges (), verrà eseguito il rollback anche del primo SaveChanges (). Come proponi di riprovare? Non puoi Ecco perché EF retry supporta solo un singolo SaveChanges () per transazione.
Un modo è quello di rimuovere SaveChanges () da Demo1 () e Demo2 (), e avere un singolo SaveChanges () nel metodo chiamante invece di una transazione.
Un altro modo è per voi di rilevare l'eccezione nel metodo di chiamata e orchestrare il tentativo di lì.