Ist es möglich, Linq2Sql dazu zu bringen, einen NOLOCK in seiner SQL auszugeben? Und wenn ja, wie?
Ist es möglich, Linq2Sql dazu zu bringen, einen NOLOCK in seiner SQL auszugeben? Und wenn ja, wie?
Antworten:
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
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 NOLOCK
alle auswertenden Abfragen durchführen können, für die Sie nicht NoLock
explizit geschrieben haben (wie ToListNoLock
oben 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()
.
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
}
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();
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");
}