entity-framework - entity framework nolock
Marco de la entidad con NOLOCK (9)
Aunque estoy absolutamente de acuerdo en que el uso del nivel de aislamiento de transacción no confirmado de Read es la mejor opción, pero en algún momento forzó a utilizar la sugerencia de NOLOCK a petición del administrador o el cliente y no se aceptó ninguna razón en contra de esto.
Con Entity Framework 6 puede implementar su propio DbCommandInterceptor de la siguiente manera:
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)");
}
}
}
Con esta clase en su lugar, puede aplicarla al inicio de la aplicación:
DbInterception.Add(new NoLockInterceptor());
Y desactivar de forma condicional la adición de la sugerencia NOLOCK
en las consultas para el hilo actual:
NoLockInterceptor.SuppressNoLock = true;
¿Cómo puedo usar la función NOLOCK en Entity Framework? ¿XML es la única forma de hacer esto?
Con la introducción de EF6, Microsoft recomienda usar el método BeginTransaction ().
Puede utilizar BeginTransaction en lugar de TransactionScope en EF6 + y EF Core
using (var ctx = new ContractDbContext())
using (var transaction = ctx.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
//any reads we do here will also read uncommitted data
}
Los métodos de extensión pueden hacer esto más fácil
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;
}
}
Mejorando la respuesta aceptada del Doctor Jones y usando PostSharp ;
Primero " ReadUncommitedTransactionScopeAttribute "
[Serializable]
public class ReadUncommitedTransactionScopeAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
//declare the transaction options
var transactionOptions = new TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
//declare our context
using (var scope = new TransactionScope())
{
args.Proceed();
scope.Complete();
}
}
}
}
Entonces cuando lo necesites,
[ReadUncommitedTransactionScope()]
public static SomeEntities[] GetSomeEntities()
{
using (var context = new MyEntityConnection())
{
//any reads we do here will also read uncomitted data
//...
//...
}
}
Ser capaz de agregar "NOLOCK" con un interceptor también es agradable, pero no funcionará cuando se conecte a otros sistemas de bases de datos como Oracle.
No, pero puede iniciar una transacción y establecer el nivel de aislamiento para que no se emita . Esto básicamente hace lo mismo que NOLOCK, pero en lugar de hacerlo por tabla, lo hará por todo dentro del alcance de la transacción.
Si eso suena como lo que quieres, así es cómo podrías hacerlo ...
//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();
}
No, realmente no. Entity Framework es básicamente una capa bastante estricta sobre tu base de datos real. Sus consultas están formuladas en ESQL - Entity SQL - que, en primer lugar, está dirigido a su modelo de entidad, y dado que EF soporta múltiples backends de bases de datos, realmente no puede enviar SQL "nativo" directamente a su back-end.
La sugerencia de consulta NOLOCK es algo específico de SQL Server y no funcionará en ninguna de las otras bases de datos compatibles (a menos que también hayan implementado la misma sugerencia, lo que dudo mucho).
Bagazo
Para evitar esto, creo una vista en la base de datos y aplico NOLOCK en la consulta de la vista. Luego trato la vista como una tabla dentro de EF.
Si necesita algo en general, la mejor manera en que descubrimos que es menos intrusivo que iniciar un scope de transacción cada vez, es simplemente establecer el nivel de aislamiento de transacción predeterminado en su conexión después de que haya creado su contexto de objeto ejecutando este comando simple:
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
Con esta técnica, pudimos crear un proveedor de EF simple que crea el contexto para nosotros y realmente ejecuta este comando cada vez para todo nuestro contexto, de modo que siempre estamos en "lectura no confirmada" de forma predeterminada.
Una opción es usar un procedimiento almacenado (similar a la solución de vista propuesta por Ryan) y luego ejecutar el procedimiento almacenado desde EF. De esta forma, el procedimiento almacenado realiza la lectura sucia mientras que EF simplemente canaliza los resultados.