2009-08-03 11 views
61

¿Es posible hacer que Linq2Sql emita un NOLOCK en su SQL? Y si es así, ¿cómo?NOLOCK con Linq a SQL

+0

Acabo de encontrar esta pregunta que se cruza en parte, pero de todos modos el crédito se debe: http://stackoverflow.com/questions/62963/how-do-you-extend-linq-to-sql Voy a mantener el pregunta abierta por un tiempo por las dudas. –

Respuesta

77

sí lo es, así que aquí está la entrada from my blog:

La sugerencia NOLOCK es esencialmente el mismo que envolver una consulta en una transacción cuyo "nivel de aislamiento" es conjunto de "leer no comprometidos". Significa que a la consulta no le importa si las cosas están en proceso de escribirse en las filas que está leyendo - va a leer los datos "sucios" y devolverlo como parte del conjunto de resultados.

resulta que usted puede hacer el conjunto "leer no comprometidos" cosa transacción usando los viejos System.Transactions espacio de nombres introdujo en .NET 2.0. He aquí algunos ejemplos de código:

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

Así que estoy creando un nuevo objeto TransactionScope y diciéndole que la utilice un nivel de aislamiento de lectura no confirmada . La consulta dentro de la instrucción "using" ahora actúa como si todas sus tablas estuvieran leyendo con la sugerencia NOLOCK.

Éstos son los primeros resultados de una búsqueda en Google de "LINQ nolock SQL":

InfoQ: Implementing NOLOCK with LINQ to SQL and LINQ to Entities

Matt Hamilton - LINQ to SQL and NOLOCK Hints : Mad Props!

Scott Hanselman's Computer Zen - Getting LINQ to SQL and LINQ to ...

+6

Si quería ser totalmente correcto, ninguna de estas opciones realmente "emiten un NOLOCK" en el SQL en sí; en su lugar, usan la configuración de aislamiento de la transacción. Lo mismo, pero técnicamente no es lo que hizo la pregunta. –

+3

Copió el texto de su blog, por lo que nadie tiene que hacer clic en los enlaces para obtener la respuesta. – Eric

+1

Sin preocupaciones. Mi punto principal es que esto es fácilmente detectable en Google sin tener que preguntar aquí. Esta pregunta probablemente usurpe el lugar # 1 en Google para esta búsqueda ahora. :) –

7

Aquí es un método de extensión para usar con 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(); 
    } 
} 

A continuación, se puede llamar como:

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

Esto es realmente agradable solución. Limpio y simple! – Colin

10

Una forma sencilla puede ser la de ejecutar un comando en su clase DataContext

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

    // Your SQL query 
} 
+0

Quizás esta respuesta incrustada con la respuesta de los Reyes sea agradable de tener – Pierre

2

En mi caso, Entity Framework 5 (basado en la respuesta @Soppus):

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

Gracias, su solución evita la "COMException: el administrador de transacciones ha deshabilitado su soporte para transacciones remotas/de red". eso puede agregarse a otras solicitudes. –

15

Además de LinqPad My Extensions addition de theking:

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

El último significa que puede hacer un NOLOCK en cualquier consulta de evaluación para la que no haya escrito NoLock explícitamente (como he obtenido para ToListNoLock anterior). Entonces, por ejemplo:

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

evaluará la consulta con NOLOCK.

Tenga en cuenta que debe asegurarse de que está evaluando la consulta. P.ej. .NoLock((x)=>x.Distinct()).Count().Dump() no hará nada útilmente diferente de .Distinct().Count().Dump().

+1

Esto se puede arreglar un poco añadiendo un método estático 'GetReadUnCommittedScope()' y luego haciendo 'using (var txn = GetReadUncommittedScope())' – asherber

+0

@asherber Done. –