Как я могу использовать функцию NOLOCK в Entity Framework? XML - единственный способ сделать это?
Вопрос
Entity Framework с NOLOCK
Ответы
Ответ 1 · рейтинг 211 · Doctor Jones
Нет, но вы можете начать транзакцию и установить уровень изоляции для чтения без фиксации. По сути, это то же самое, что и 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();
}
Ответ 2 · рейтинг 86 · Alexandre
Методы расширения могут упростить эту задачу
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;
}
}
Ответ 3 · рейтинг 28 · Frank.Germain
Если вам нужно что-то в целом, лучший способ, который, как мы обнаружили, менее навязчивый, чем фактический запуск области транзакции каждый раз, - это просто установить уровень изоляции транзакции по умолчанию для вашего соединения после того, как вы создали контекст объекта, выполнив эту простую команду:
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
С помощью этого метода мы смогли создать простой поставщик EF, который создает для нас контекст и фактически запускает эту команду каждый раз для всего нашего контекста, так что по умолчанию мы всегда находимся в состоянии "чтение незафиксировано".
Ответ 4 · рейтинг 22 · Yuriy Rozhovetskiy
Хотя я абсолютно согласен с тем, что использование уровня изоляции "Чтение незафиксированных транзакций" - лучший выбор, но какое-то время вы заставляли использовать подсказку 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;
Ответ 5 · рейтинг 10 · myuce
Улучшение принятого ответа доктора Джонса и использование 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 как таковые.
Ответ 6 · рейтинг 7 · Ryan Galloway
Чтобы обойти это, я создаю представление в базе данных и применяю NOLOCK к запросу представления. Затем я рассматриваю представление как таблицу в EF.
Ответ 7 · рейтинг 5 · Ali
С введением 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
}
Ответ 8 · рейтинг 2 · marc_s
Нет, не совсем - Entity Framework - это, по сути, довольно строгий уровень над вашей реальной базой данных. Ваши запросы формулируются на ESQL - Entity SQL - который в первую очередь ориентирован на вашу модель сущностей, а поскольку EF поддерживает несколько бэкэндов базы данных, вы не можете отправлять "родной" SQL прямо в бэкэнд.
Подсказка запроса NOLOCK специфична для SQL Server и не будет работать ни с одной из других поддерживаемых баз данных (если только они не реализовали ту же подсказку, в чем я сильно сомневаюсь).
Марк
Ответ 9 · рейтинг 1 · Rafiki
Один из вариантов - использовать хранимую процедуру (аналогичную представлению, предложенному Райаном), а затем выполнить хранимую процедуру из EF. Таким образом, хранимая процедура выполняет грязное чтение, в то время как EF просто передает результаты.
Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.
Похожие материалы
- Поставщик службы данных WCF против Code First Context с использованием наследования в моделях
- Вычисляемый столбец edmx
- Почему свойства навигации должны быть общедоступными для создания прокси?
- Магическое число в заголовке GZip неверно. Убедитесь, что вы передаете поток GZip
- TransactionScope и хранимая процедура?
- Как узнать, изменил ли пользователь данные с помощью источника привязки?