[Entity-Framework] Entity Framework с NOLOCK


Answers

Методы расширения могут сделать это проще

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

Как я могу использовать функцию NOLOCK в Entity Framework? Является ли XML единственным способом сделать это?




Чтобы обойти это, я создаю представление о базе данных и применяю NOLOCK к запросу вида. Затем я рассматриваю представление как таблицу в EF.




Хотя я абсолютно согласен с тем, что использование уровня изоляции транзакций Read Uncommitted - лучший выбор, но некоторое время вы вынуждены использовать подсказку NOLOCK по запросу менеджера или клиента и никаких оснований против этого принято.

С Entity Framework 6 вы можете реализовать собственный DbCommandInterceptor следующим образом:

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

С помощью этого класса вы можете применить его при запуске приложения:

DbInterception.Add(new NoLockInterceptor());

И условно отключить добавление подсказки NOLOCK в запросы для текущего потока:

NoLockInterceptor.SuppressNoLock = true;



С введением EF6 Microsoft рекомендует использовать метод BeginTransaction ().

Вы можете использовать BeginTransaction вместо TransactionScope в EF6 + и 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
}





Links