79 votes

NOLOCK avec Linq to SQL

Est-il possible de faire en sorte que Linq2Sql émette un NOLOCK dans son SQL ? Et si oui, comment ?

0 votes

Je viens de trouver cette question qui recoupe en partie la mienne, mais je vous en remercie quand même : stackoverflow.com/questions/62963/how-do-you-extend-linq-to-sql Je vais laisser la question ouverte pendant un moment, juste au cas où.

95voto

Matt Hamilton Points 98268

Oui, c'est le cas, alors voici l'inscription de mon blog :

L'indice NOLOCK est essentiellement la même chose que d'envelopper une requête dans un transaction dont le "niveau d'isolation" est est réglé sur "read uncommitted". Cela signifie que la requête ne se soucie pas de savoir si un élément est en train d'être écrit sur sur les lignes qu'elle lit, elle va le faire lire ces données "sales" et les retourner dans l'ensemble des résultats.

Il s'avère que vous pouvez faire le tout transaction "read uncommitted" en utilisant l'ancien espace de nom System.Transactions introduit en .NET 2.0. Voici un exemple de code :

using (var txn = new TransactionScope(
    TransactionScopeOption.Required, 
    new TransactionOptions
    {
        IsolationLevel = IsolationLevel.ReadUncommitted
    }
))
{
    // Your LINQ to SQL query goes here
}

Je crée donc un nouvel objet TransactionScope et je lui demande d'utiliser une méthode niveau d'isolation read-uncommitted. La requête requête dans l'instruction "using" agit maintenant agit comme si toutes ses tables étaient lues avec l'indice NOLOCK.

Voici les premiers résultats d'une recherche Google pour "linq sql nolock" :

InfoQ : Implémentation de NOLOCK avec LINQ to SQL et LINQ to Entities

Matt Hamilton - LINQ to SQL et les astuces NOLOCK : Mad Props !

Scott Hanselman's Computer Zen - Obtenir LINQ to SQL et LINQ to ...

6 votes

Si je voulais être tout à fait correct, aucune de ces options n'émet réellement un NOLOCK dans le SQL lui-même - elles utilisent plutôt le paramètre d'isolation de la transaction. C'est la même chose, mais ce n'est pas techniquement ce que la question demandait.

3 votes

J'ai copié le texte de votre blog, afin que personne ne doive cliquer sur des liens pour trouver la réponse.

1 votes

Ne vous inquiétez pas. Ce que je voulais dire, c'est qu'il est facile de trouver ces informations sur Google sans avoir à les demander ici. Cette question va probablement usurper la première place sur Google pour cette recherche maintenant :)

26voto

Mark Hurd Points 4746

Suite à la décision du Roi LinqPad My Extensions ajout :

public static IQueryable<T> DumpNoLock<T>(this IQueryable<T> query)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return query.Dump();
    }   
}

public static System.Transactions.TransactionScope GetNewReadUncommittedScope()
{
    return new System.Transactions.TransactionScope(
        System.Transactions.TransactionScopeOption.RequiresNew,
        new System.Transactions.TransactionOptions
        {
            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
        });
}
public static IQueryable<T> DumpNoLock<T>(this IQueryable<T> query, string description)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return query.Dump(description);
    }   
}

public static List<T> ToListNoLock<T>(this IQueryable<T> query)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return query.ToList();
    }   
}

public static U NoLock<T,U>(this IQueryable<T> query, Func<IQueryable<T>,U> expr)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return expr(query);
    }   
}

Le dernier signifie que vous pouvez faire un NOLOCK sur toutes les requêtes d'évaluation que vous n'avez pas un NoLock explicitement écrit pour (comme je l'ai fait pour ToListNoLock ci-dessus). Ainsi, par exemple :

somequery.NoLock((x)=>x.Count()).Dump();

évaluera la requête avec NOLOCK .

Notez que vous devez vous assurer que vous évaluez la requête. Par exemple .NoLock((x)=>x.Distinct()).Count().Dump() ne fera rien d'utilement différent de .Distinct().Count().Dump() .

11voto

Soppus Points 142

Un moyen simple peut être d'exécuter une commande sur votre classe DataContext

using (var dataContext = new DataContext())
{
  dataContext.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");

  // Your SQL query
}

0 votes

Peut-être que cette réponse incorporée à la réponse de King sera un atout supplémentaire.

9voto

theKing Points 320

Voici une méthode d'extension à utiliser avec LINQPAD

    public static IQueryable<T> Dump2<T>(this IQueryable<T> query)
{
    using (var txn = new System.Transactions.TransactionScope(TransactionScopeOption.RequiresNew, 
        new TransactionOptions
        {       
            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
        }))
    {
        return query.Dump();
    }   
}

Vous pouvez alors l'appeler comme :

MyTable.Where(t => t.Title = "Blah").Dump2();

3voto

Akira Yamamoto Points 982

Dans mon cas, Entity Framework 5 (basé sur la réponse de @Soppus) :

private FoobarEntities db = new FoobarEntities();
public FoobarController()
{
    db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}

1 votes

Merci, votre solution évite le "COMException : Le gestionnaire de transactions a désactivé son support pour les transactions à distance/réseau" qui peut s'ajouter à d'autres requêtes.

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