NOLOCK mit Linq to SQL

70

Ist es möglich, Linq2Sql dazu zu bringen, einen NOLOCK in seiner SQL auszugeben? Und wenn ja, wie?

Scott McKenzie
quelle
Ich habe gerade diese Frage gefunden, die teilweise überkreuzt, aber trotzdem fällig ist: stackoverflow.com/questions/62963/how-do-you-extend-linq-to-sql Ich werde die Frage für alle Fälle für eine Weile offen halten.
Scott McKenzie

Antworten:

86

Ja, also hier ist der Eintrag aus meinem Blog :

Der NOLOCK-Hinweis entspricht im Wesentlichen dem Umschließen einer Abfrage in eine Transaktion, deren "Isolationsstufe" auf "nicht festgeschrieben lesen" gesetzt ist. Dies bedeutet, dass es der Abfrage egal ist, ob gerade etwas in die Zeilen geschrieben wird, aus denen es liest. Sie liest diese "schmutzigen" Daten und gibt sie als Teil der Ergebnismenge zurück.

Es stellt sich heraus, dass Sie die gesamte Transaktion "nicht festgeschrieben lesen" mit dem in .NET 2.0 eingeführten alten System.Transactions-Namespace ausführen können. Hier ist ein Beispielcode:

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

Ich erstelle also ein neues TransactionScope-Objekt und fordere es auf, eine nicht festgeschriebene Isolationsstufe zum Lesen zu verwenden. Die Abfrage in der Anweisung "using" verhält sich jetzt so, als würden alle Tabellen mit dem NOLOCK-Hinweis gelesen.

Hier sind die ersten Ergebnisse einer Google-Suche nach "linq sql nolock":

InfoQ: Implementierung von NOLOCK mit LINQ to SQL und LINQ to Entities

Matt Hamilton - LINQ zu SQL und NOLOCK Hinweise: Mad Props!

Scott Hanselmans Computer Zen - LINQ zu SQL und LINQ zu ...

Matt Hamilton
quelle
6
Wenn ich völlig korrekt sein wollte, "emittiert" keine dieser Optionen tatsächlich einen NOLOCK im SQL selbst - sie verwenden stattdessen die Isolationseinstellung der Transaktion. Das Gleiche, aber technisch nicht das, was die Frage stellte.
Matt Hamilton
3
Kopierte den Text aus Ihrem Blog, sodass niemand durch Links klicken muss, um zur Antwort zu gelangen.
Eric
2
@ Matt: Das ist der Punkt! Erstellen Sie eine kanonische Quelle! Siehe: meta.stackexchange.com/questions/8724/…
Eric
7
Müsste mit Matt über den Diebstahl von Inhalten einverstanden sein. Matt nahm sich die Zeit, um den Beitrag in seinem Blog zu schreiben. Jetzt bekommt SOF den Verkehr
Andrew Harry
4
Sie können Antworten in einem Blog nicht hoch- und runterstimmen, daher gibt es keine Möglichkeit, die Qualität dort zu überprüfen. Ich denke, das Kopieren kurzer Schnipsel nach SO mit Attribution ist der richtige Weg.
Kirk Woll
23

Weiter zum LinqPad- Zusatz des KönigsMy Extensions :

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);
    }   
}

Letzteres bedeutet, dass Sie NOLOCKalle auswertenden Abfragen durchführen können, für die Sie nicht NoLockexplizit geschrieben haben (wie ToListNoLockoben beschrieben). Also zum Beispiel:

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

wird die Abfrage mit auswerten NOLOCK.

Beachten Sie, dass Sie sicherstellen müssen, dass Sie die Abfrage auswerten. ZB .NoLock((x)=>x.Distinct()).Count().Dump()macht nichts sinnvoll anderes als .Distinct().Count().Dump().

Mark Hurd
quelle
11

Eine einfache Möglichkeit besteht darin, einen Befehl für Ihre DataContext-Klasse auszuführen

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

  // Your SQL query
}
Soppus
quelle
Vielleicht ist diese Antwort, eingebettet in die Antwort der Könige, eine schöne Antwort
Pierre
8

Hier ist eine Erweiterungsmethode für 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();
    }   
}

Dann können Sie es nennen als:

MyTable.Where(t => t.Title = "Blah").Dump2();
der König
quelle
2

In meinem Fall Entity Framework 5 (basierend auf der Antwort von @Soppus):

private FoobarEntities db = new FoobarEntities();
public FoobarController()
{
    db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}
Akira Yamamoto
quelle
1
Dank Ihrer Lösung vermeiden Sie die "COMException: Der Transaktionsmanager hat die Unterstützung für Remote- / Netzwerktransaktionen deaktiviert." das kann an andere Anfragen angehängt werden.
Olivier de Rivoyre