Как я могу использовать NOLOCK
функцию в Entity Framework? XML - единственный способ сделать это?
c#
entity-framework
ado.net
OneSmartGuy
источник
источник
Методы расширения могут сделать это проще
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; } }
источник
Если вам нужно что-то в целом, лучший способ, который, как мы обнаружили, менее навязчивый, чем фактический запуск области транзакции каждый раз, - это просто установить уровень изоляции транзакции по умолчанию для вашего соединения после того, как вы создали контекст объекта, выполнив эту простую команду:
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
С помощью этого метода мы смогли создать простой поставщик EF, который создает для нас контекст и фактически запускает эту команду каждый раз для всего нашего контекста, так что по умолчанию мы всегда находимся в состоянии «чтение не зафиксировано».
источник
Transactions running at the READ UNCOMMITTED level do not issue shared locks
. Это означает, что вы должны работать в рамках транзакции, чтобы получить выгоду. (взято из msdn.microsoft.com/en-gb/library/ms173763.aspx ). Ваш подход может быть менее навязчивым, но он ничего не даст, если вы не используете транзакцию.SET TRANSACTION ISOLATION LEVEL...
влияет на свойство уровня соединения и, следовательно, влияет на все операторы SQL, сделанные с этой точки (для соединения THAT), если только это не переопределено подсказкой запроса. Такое поведение существует, по крайней мере, с SQL Server 2000 и, вероятно, раньше.CREATE TABLE ##Test(Col1 INT); BEGIN TRAN; SELECT * FROM ##Test WITH (TABLOCK, XLOCK);
. Откройте другой запрос (# 2) и запустить:SELECT * FROM ##Test;
. SELECT не вернется, поскольку он блокируется все еще открытой транзакцией на вкладке №1, которая использует эксклюзивную блокировку. Отмените выбор в # 2. ВыполнитеSET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
один раз на вкладке №2. Снова запустите только SELECT на вкладке № 2, и она вернется. Обязательно запуститеROLLBACK
вкладку №1.Хотя я абсолютно согласен с тем, что использование уровня изоляции 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;
источник
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { if (!SuppressNoLock) command.CommandText = $"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;{Environment.NewLine}{command.CommandText}"; base.ReaderExecuting(command, interceptionContext); }
Улучшение принятого ответа доктора Джонса и использование 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 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 }
источник
Нет, не совсем - Entity Framework - это, по сути, довольно строгий уровень над вашей реальной базой данных. Ваши запросы формулируются на ESQL - Entity SQL - который в первую очередь ориентирован на вашу модель сущностей, а поскольку EF поддерживает несколько бэкэндов базы данных, вы действительно не можете отправлять «родной» SQL прямо в бэкэнд.
Подсказка запроса NOLOCK специфична для SQL Server и не будет работать ни с одной из других поддерживаемых баз данных (если они также не реализовали ту же подсказку - в чем я сильно сомневаюсь).
Марк
источник
Database.ExecuteSqlCommand()
илиDbSet<T>.SqlQuery()
.(NOLOCK)
- см. Плохие привычки, чтобы пнуть - повсюду ставить NOLOCK - НЕ РЕКОМЕНДУЕТСЯ использовать его везде - совсем наоборот!Один из вариантов - использовать хранимую процедуру (аналогичную представлению, предложенному Райаном), а затем выполнить хранимую процедуру из EF. Таким образом, хранимая процедура выполняет грязное чтение, а EF просто передает результаты.
источник