7

Per affrontare timeout SQL che sto cercando di utilizzare SqlAzureExecutionStrategy (https://msdn.microsoft.com/en-us/data/dn456835.aspx)Come utilizzare SqlAzureExecutionStrategy e "nolock"

Il problema che sto funzionando in è che impedisce "le operazioni avviate utente" che sembrano essere la raccomandata modo di implementare "con (nolock)" in EF (http://www.hanselman.com/blog/GettingLINQToSQLAndLINQToEntitiesToUseNOLOCK.aspx, NOLOCK with Linq to SQL).

esempio di codice

public AspnetUser GetAspnetUserByUserName(string userName) 
    { 
     using (var tx = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted })) 
     { 
      return context.AspnetUsers.Where(x => x.UserName == userName).FirstOrDefault(); 
     } 
    } 

tiri errore

La strategia di esecuzione configurato 'SqlAzureExecutionStrategy' non supporta le transazioni utente iniziati. Vedere http://go.microsoft.com/fwlink/?LinkId=309381 per ulteriori informazioni.

Ho visto le risposte che dicono di spegnere lo SqlAzureExecutionStrategy su una base per chiamata, ma che avrebbe vanificato l'obiettivo di utilizzarlo, se tutta la mia letture ignorato la strategia. È possibile avere sia "NoLock" che SqlAzureExecutionStrategy

risposta

11

SqlAzureExecutionStrategy non supporta le transazioni avviate al di fuori dell'azione da ritentare. Per ovviare a questa limitazione si avrebbe bisogno di sospendere la strategia, creare la portata dell'operazione e fare il lavoro come un'azione che si passa manualmente alla strategia di esecuzione necessario riprovare:

public AspnetUser GetAspnetUserByUserName(string userName) 
{ 
    new SuspendableSqlAzureExecutionStrategy().Execute(() => 
     { 
      using (var tx = new TransactionScope(
        TransactionScopeOption.Required, 
        new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted })) 
      { 
       return context.AspnetUsers.Where(x => x.UserName == userName).FirstOrDefault(); 
      } 
     }); 
} 

Qui sto usando in alternativa alla la strategia sospendibile da https://msdn.microsoft.com/en-us/data/dn307226 che sospenderà automaticamente qualsiasi invocazioni nidificati:

using System.Data.Entity.Infrastructure; 
using System.Data.Entity.SqlServer; 
using System.Data.Entity.Utilities; 
using System.Runtime.Remoting.Messaging; 
using System.Threading; 
using System.Threading.Tasks; 

public class SuspendableSqlAzureExecutionStrategy : IDbExecutionStrategy 
{ 
    private readonly IDbExecutionStrategy _azureExecutionStrategy; 

    public SuspendableSqlAzureExecutionStrategy() 
    { 
     _azureExecutionStrategy = new SqlAzureExecutionStrategy(); 
    } 

    private static bool Suspend 
    { 
     get { return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false; } 
     set { CallContext.LogicalSetData("SuspendExecutionStrategy", value); } 
    } 

    public bool RetriesOnFailure 
    { 
     get { return !Suspend; } 
    } 

    public virtual void Execute(Action operation) 
    { 
     if (!RetriesOnFailure) 
     { 
      operation(); 
      return; 
     } 

     try 
     { 
      Suspend = true; 
      _azureExecutionStrategy.Execute(operation); 
     } 
     finally 
     { 
      Suspend = false; 
     } 
    } 

    public virtual TResult Execute<TResult>(Func<TResult> operation) 
    { 
     if (!RetriesOnFailure) 
     { 
      return operation(); 
     } 

     try 
     { 
      Suspend = true; 
      return _azureExecutionStrategy.Execute(operation); 
     } 
     finally 
     { 
      Suspend = false; 
     } 
    } 

    public virtual async Task ExecuteAsync(Func<Task> operation, CancellationToken cancellationToken) 
    { 
     if (!RetriesOnFailure) 
     { 
      await operation(); 
      return; 
     } 

     try 
     { 
      Suspend = true; 
      await _azureExecutionStrategy.ExecuteAsync(operation, cancellationToken); 
     } 
     finally 
     { 
      Suspend = false; 
     } 
    } 

    public virtual async Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> operation, CancellationToken cancellationToken) 
    { 
     if (!RetriesOnFailure) 
     { 
      return await operation(); 
     } 

     try 
     { 
      Suspend = true; 
      return await _azureExecutionStrategy.ExecuteAsync(operation, cancellationToken); 
     } 
     finally 
     { 
      Suspend = false; 
     } 
    } 
} 

public class MyConfiguration : DbConfiguration 
{ 
    public MyConfiguration() 
    { 
     SetExecutionStrategy("System.Data.SqlClient",() => new SuspendableSqlAzureExecutionStrategy()); 
    } 
} 
+0

cercherò di verificare ciò, questa settimana per farvi sapere come funziona grazie –

+0

l'unica cosa che io non sono chiare su questo è il motivo per cui La sospensione deve essere pubblica. Anche dare una prova ora, sembra più pulito della versione MSDN. –

+0

Funziona bene. Sospensione aggiornata per essere privata dalla mia parte, ma questa è un'implementazione molto carina, grazie per quello. –

Problemi correlati