2009-05-29 6 views

ответ

196

Нет, но вы можете начать транзакцию и установить isolation level to read uncommited. Это по сути делает то же самое, что и 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(); 
} 
+0

Excellent @DoctaJonez Было ли что-то новое в EF4 для этого? – FMFF

+0

@FMFF Я не знаю, было ли что-то новое для EF4. Я знаю, что приведенный выше код работает с EFv1 и выше. –

+0

что было бы последствием? если кто-то опустил транзакциюScope.Complete() в упомянутом выше блоке? Как вы думаете, я должен задать еще один вопрос? –

2

Нет, на самом деле - структура Entity Framework в основном довольно строгий уровень над вашей фактической базой данных. Ваши запросы сформулированы в ESQL - Entity SQL, который в первую очередь нацелен на вашу модель сущности, и поскольку EF поддерживает несколько баз данных, вы действительно не можете отправлять «родной» SQL непосредственно на ваш сервер.

Подсказка запроса NOLOCK является специфической вещью SQL Server и не будет работать ни на одной из других поддерживаемых баз данных (кроме случаев, когда они также реализовали один и тот же намек, на что я очень сомневаюсь).

Марк

+0

Этот ответ устарел - вы можете использовать NOLOCK, как упомянули другие, и вы можете выполнить «собственный» SQL, используя 'Database.ExecuteSqlCommand()' или 'DbSet .SqlQuery()'. – Dunc

+1

@ Dunc: спасибо за downvote - btw: вы должны *** НЕ использовать *** (NOLOCK) 'в любом случае - см. [Bad Habits to kick - put NOLOCK везде] (http://blogs.sqlsentry.com/ aaronbertrand/bad-habits-nolock-везде /) - это НЕ РЕКОМЕНДУЕТСЯ *** использовать это везде - совсем наоборот! –

+0

Добро пожаловать. – Dunc

5

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

26

Если вам нужно что-то в целом, лучший способ, который мы обнаружили, который менее навязчив, чем запуск транзакции каждый раз, заключается в том, чтобы просто установить уровень изоляции транзакций по умолчанию в вашем соединении после создания контекста объекта, выполнив это простая команда:

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

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

с помощью этого метода, мы смогли создать простой поставщика EF, который создает контекст для нас, и на самом деле работает эту команду каждый раз, когда для всех наших условий, с тем, что мы» re всегда в "read uncommitted" по умолчанию.

+2

Установка уровня изоляции транзакции не будет иметь никакого эффекта , Вам действительно нужно работать в транзакции, чтобы она имела какой-либо эффект. Документация MSDN для READ UNCOMMITTED утверждает, что транзакции, выполняемые на уровне READ UNCOMMITTED, не выдают совместно используемые блокировки. Это означает, что вы должны работать в рамках транзакции, чтобы получить выгоду. (взято из http://msdn.microsoft.com/en-gb/library/ms173763.aspx). Ваш подход может быть менее навязчивым, но он ничего не добьется, если вы не используете транзакцию. –

+3

Документация MSDN гласит: «Управляет управлением версиями Transact-SQL, связанными с блокировкой и строкой, выдаваемыми при подключении к SQL Server». и «Указывает, что операторы могут читать строки, которые были изменены другими транзакциями, но еще не выполнены». Это заявление, которое я написал, затрагивает все инструкции SQL, которое находится внутри транзакции или нет. Мне не нравится противоречить людям в Интернете, но вы явно ошибаетесь в этом, основываясь на нашем использовании этого заявления в большой производственной среде. Не думай о вещах, ПОПРОБУЙТЕ ИХ! –

+0

Я пробовал их, у нас есть среда с высокой нагрузкой, где не выполнение запросов в одной из этих областей транзакций (и соответствующей транзакции) приведет к тупиковой ситуации. Мои наблюдения были сделаны на сервере SQL 2005, поэтому я не знаю, изменилось ли поведение с тех пор. Поэтому я рекомендую это; если вы укажете уровень незанятой изоляции, но продолжаете испытывать взаимоблокировки, попробуйте поместить свои запросы в транзакцию. Если вы не столкнетесь с взаимоблокировками, не создавая транзакцию, то достаточно справедливы. –

74

метода расширения может сделать это проще

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

Хорошая работа, мне нравится это решение. –

+2

Человек я люблю методы расширения. Это потрясающе! –

+0

Использование этого в моем проекте приводит к тому, что пул соединений полностью используется, что приводит к исключению. не может понять, почему. У кого-нибудь еще есть проблемы? Какие-либо предложения? –

18

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

С Entity Framework 6 вы можете реализовать собственный DbCommandInterceptor как это:

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

DbInterception.Add(new NoLockInterceptor()); 

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

NoLockInterceptor.SuppressNoLock = true; 
+0

Мне нравится это решение, хотя я немного изменил регулярное выражение: – Russ

+2

(? \] AS \ [Extent \ d + \] (?! WITH \ (NOLOCK \))), чтобы предотвратить добавление nolock в производную таблицу, которая вызывает ошибку. :) – Russ

+0

Настройка SuppressNoLock на уровне потока - это удобный способ, но легко забыть отменить логическое значение, вы должны использовать функцию, возвращающую IDisposable, метод Dispose может просто снова установить bool в false. Также ThreadStatic на самом деле не совместим с async/await: http://stackoverflow.com/questions/13010563/using-threadstatic-variables-with-async-await – Jaap

9

Усовершенствование на принятом Doctor Jones и использование 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 как таковые.

0

Один из вариантов заключается в использовании хранимой процедуры (аналогично решению вида, предложенной Райаном), а затем выполнить хранимую процедуру из EF. Таким образом, хранимая процедура выполняет грязное чтение, а EF просто передает результаты.