Я использую Entity Framework 6 в проекте MVC 5. Как вам известно, запросы SELECT
в SQL Server работают быстрее и эффективнее, если мы используем WITH (NOLOCK)
в них. Я проверил несколько операторов SQL SELECT, созданных Entity Framework 6, и понял, что ни один из них не содержит NOLOCK. Я не хочу использовать транзакции в своих операциях выборки для чтения из незафиксированных транзакций. How can I enforce EF 6 to use NOLOCK in the underneath generated SELECT statements
? Ваше мнение очень ценится. Спасибо.
Get Entity Framework 6 использует NOLOCK в своих инструкциях SELECT
Ответ 1
Прежде всего... НИКОГДА НИКОГДА НЕ используйте NOLOCK для каждого SQL-заявления. Это может поставить под угрозу целостность ваших данных.
Его, как и любой другой запрос, подсказывают механизм, который вы должны использовать, только когда делаете что-то необычное.
Невозможно сообщить провайдеру EF визуализацию подсказки NoLock. Если вам действительно нужно прочитать незафиксированные данные, у вас есть следующий вариант.
-
Напишите свой собственный EntityFramework Provider.
-
Используйте командный перехватчик для изменения инструкции до ее казнены. http://msdn.microsoft.com/en-us/data/dn469464.aspx
-
Используйте TransactionScope с IsolationLevel.ReadUncommited.
Я знаю, что вы сказали, что не хотите использовать Транзакции, но это единственный доступный способ чтения незафиксированных данных. Кроме того, это не приводит к большим накладным расходам, поскольку каждое выражение в SQL Server "неявно" выполняется в транзакции.
using (new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
using (var db = new MyDbContext()) {
// query
}
}
Ответ 2
Я согласен с тем, что codeworx говорит так, что Read Uncommitted может быть опасным. Если вы можете жить с грязными чтениями, пойдите для этого.
Я нашел способ сделать эту работу без изменения чего-либо в текущих запросах.
Вам нужно создать DbCommandInterceptor следующим образом:
public class IsolationLevelInterceptor : DbCommandInterceptor
{
private IsolationLevel _isolationLevel;
public IsolationLevelInterceptor(IsolationLevel level)
{
_isolationLevel = level;
}
//[ThreadStatic]
//private DbCommand _command;
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
SetTransaction(command);
}
public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
SetTransaction(command);
}
public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
SetTransaction(command);
}
private void SetTransaction(DbCommand command)
{
if (command != null)
{
if (command.Transaction == null)
{
var t = command.Connection.BeginTransaction(_isolationLevel);
command.Transaction = t;
//_command = command;
}
}
}
}
то на cctor (статический конструктор вашего dbcontext) просто добавьте перехватчик в DbInfrastructure коллекций фреймворков сущностей.
DbInterception.Add(new IsolationLevelInterceptor());
это будет для каждой команды, которую EF отправляет в хранилище, обертывает транзакцию с этим уровнем изоляции.
В моем случае хорошо работает, поскольку мы записываем данные через API, где эти данные не основаны на показаниях из базы данных. (данные могут быть повреждены из-за грязных чтений) и поэтому отлично работают.