[C#] NOLOCK이있는 엔터티 프레임 워크

NOLOCKEntity Framework에서이 기능을 사용하려면 어떻게 해야합니까? XML이이를 수행 할 수있는 유일한 방법입니까?



답변

아니요, 그러나 트랜잭션을 시작하고 격리 수준을 커밋되지 않은 읽기로 설정할 수 있습니다 . 이것은 본질적으로 NOLOCK과 동일하지만 테이블 단위로 수행하는 대신 트랜잭션 범위 내의 모든 항목에 대해 수행합니다.

그것이 원하는 것처럼 들리면 다음과 같이하십시오.

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


답변

확장 방법으로 이것을 쉽게 만들 수 있습니다

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


답변

큰 무언가가 필요한 경우 실제로 매번 transactionscope를 시작하는 것보다 덜 방해가되는 가장 좋은 방법은 다음 간단한 명령을 실행하여 객체 컨텍스트를 만든 후 연결에서 기본 트랜잭션 격리 수준을 설정하는 것입니다.

this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");

http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx

이 기술을 사용하여 컨텍스트를 작성하고 모든 컨텍스트에 대해 매번이 명령을 실행하여 기본적으로 항상 “커밋되지 않은 읽기”상태가되도록하는 간단한 EF 제공자를 작성할 수있었습니다.


답변

커밋되지 않은 읽기 트랜잭션 격리 수준을 사용하는 것이 최선의 선택이라는 데 전적으로 동의했지만 언젠가는 관리자 또는 클라이언트의 요청에 따라 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;


답변

닥터 존스 의 대답을 향상 시키고 PostSharp 사용 ;

첫 번째 ” 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();
            }
        }
    }
}

그런 다음 필요할 때마다

    [ReadUncommitedTransactionScope()]
    public static SomeEntities[] GetSomeEntities()
    {
        using (var context = new MyEntityConnection())
        {
            //any reads we do here will also read uncomitted data
            //...
            //...

        }
    }

인터셉터로 “NOLOCK”을 추가 할 수 있다는 것도 좋지만 Oracle과 같은 다른 데이터베이스 시스템에 연결할 때는 작동하지 않습니다.


답변

이 문제를 해결하기 위해 데이터베이스에서 뷰를 만들고 뷰 쿼리에 NOLOCK을 적용합니다. 그런 다음 뷰를 EF 내의 테이블로 취급합니다.


답변

EF6이 도입되면 BeginTransaction () 메서드를 사용하는 것이 좋습니다.

EF6 + 및 EF Core에서 TransactionScope 대신 BeginTransaction을 사용할 수 있습니다.

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
}