142 votes

Entity Framework avec NOLOCK

Comment utiliser la fonction NOLOCK sur Entity Framework? XML est-il le seul moyen de faire cela?

210voto

Doctor Jones Points 11502

Non, mais vous pouvez lancer une transaction et définir le niveau d'isolement à lire non validé . Cela fait essentiellement la même chose que NOLOCK, mais au lieu de le faire par table, il le fera pour tout ce qui est dans la portée de la transaction.

Si cela ressemble à ce que vous voulez, voici comment vous pouvez le faire ...

 //declare the transaction options
var transactionOptions = new System.Transactions.TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
//declare our context
using (var context = new MyEntityConnection())
{
    //any reads we do here will also read uncomitted data
    //...
    //...
    //don't forget to complete the transaction scope
    transactionScope.Complete();
}
 

86voto

Alexandre Points 1923

Les méthodes d'extension peuvent faciliter cela

 public static List<T> ToListReadUncommitted<T>(this IQueryable<T> query)
{
    using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
    {
        List<T> toReturn = query.ToList();
        scope.Complete();
        return toReturn;
    }
}

public static int CountReadUncommitted<T>(this IQueryable<T> query)
{
    using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
    {
        int toReturn = query.Count();
        scope.Complete();
        return toReturn;
    }
}
 

28voto

Frank.Germain Points 150

Si vous avez besoin de quelque chose de grand, le meilleur moyen que nous avons trouvé moins intrusive que le commencement d'une transactionscope à chaque fois, c'est simplement de définir la valeur par défaut niveau d'isolation de transaction sur votre connexion une fois que vous avez créé votre contexte de l'objet par l'exécution de cette commande simple:

this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");

http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx

Avec cette technique, nous avons été en mesure de créer un simple EF fournisseur qui crée le cadre pour nous et exécute cette commande à chaque fois pour toutes de notre contexte, de sorte que nous sommes toujours en "read uncommitted" par défaut.

22voto

Yuriy Rozhovetskiy Points 14033

Même si je suis absolument d'accord que l'utilisation de Read Uncommitted niveau d'isolation de transaction est le meilleur choix, mais un certain temps vous a forcé à utiliser NOLOCK information à la demande du gestionnaire ou d'un client et pas de raisons contre cette acceptée.

Avec Entity Framework 6 vous pouvez mettre en œuvre leurs propres DbCommandInterceptor comme ceci:

public class NoLockInterceptor : DbCommandInterceptor
{
    private static readonly Regex _tableAliasRegex = 
        new Regex(@"(?<tableAlias>AS \[Extent\d+\](?! WITH \(NOLOCK\)))", 
            RegexOptions.Multiline | RegexOptions.IgnoreCase);

    [ThreadStatic]
    public static bool SuppressNoLock;

    public override void ScalarExecuting(DbCommand command, 
        DbCommandInterceptionContext<object> interceptionContext)
    {
        if (!SuppressNoLock)
        {
            command.CommandText = 
                _tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
        }
    }

    public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        if (!SuppressNoLock)
        {
            command.CommandText = 
                _tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
        }
    }
}

Avec cette classe, vous pouvez l'appliquer sur démarrage de l'application:

DbInterception.Add(new NoLockInterceptor());

Et à condition de désactiver l'ajout de NOLOCK de l'indice dans les requêtes pour le thread courant:

NoLockInterceptor.SuppressNoLock = true;

7voto

Ryan Galloway Points 41

Pour contourner ce problème, je crée une vue sur la base de données et applique NOLOCK à la requête de la vue. Je traite ensuite la vue comme un tableau dans EF.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X