Как я могу использовать функцию NOLOCK
в Entity Framework? Является ли XML единственным способом сделать это?
Entity Framework с NOLOCK
Ответ 1
Нет, но вы можете начать транзакцию и установить уровень изоляции для чтения без указания. Это по сути делает то же самое, что и 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
Методы расширения могут сделать это проще
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
Если вам нужно что-то в целом, лучший способ, который мы обнаружили, который менее навязчив, чем фактический запуск транзакции каждый раз, заключается в том, чтобы просто установить уровень изоляции транзакций по умолчанию в вашем соединении после создания контекста объекта, выполнив этот простой команда:
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
С помощью этой методики мы смогли создать простого поставщика EF, который создает для нас контекст и на самом деле запускает эту команду каждый раз для всего нашего контекста, чтобы по умолчанию мы всегда читали uncommitted.
Ответ 4
Хотя я абсолютно согласен с тем, что использование режима изоляции 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;
Ответ 5
Усиление на Доктор Джонс принял ответ и использовал 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
Чтобы обойти это, я создаю представление о базе данных и применяю NOLOCK к запросу вида. Затем я рассматриваю представление как таблицу в EF.
Ответ 7
Нет, не совсем - Entity Framework в основном довольно строгий уровень над вашей реальной базой данных. Ваши запросы сформулированы в ESQL - Entity SQL, который в первую очередь нацелен на вашу модель сущности, и поскольку EF поддерживает несколько баз данных, вы действительно не можете отправлять "родной" SQL непосредственно на ваш сервер.
Подсказка запроса NOLOCK является специфической вещью SQL Server и не будет работать ни на одной из других поддерживаемых баз данных (кроме тех случаев, когда они также реализовали один и тот же подсказку, на что я очень сомневаюсь).
Марк
Ответ 8
С введением 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
}
Ответ 9
Один из вариантов заключается в использовании хранимой процедуры (аналогично решению вида, предложенной Райаном), а затем выполнить хранимую процедуру из EF. Таким образом, хранимая процедура выполняет грязное чтение, а EF просто передает результаты.