Подтвердить что ты не робот

Get Entity Framework 6 использует NOLOCK в своих инструкциях SELECT

Я использую 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? Ваше мнение очень ценится. Спасибо.

4b9b3361

Ответ 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, где эти данные не основаны на показаниях из базы данных. (данные могут быть повреждены из-за грязных чтений) и поэтому отлично работают.