У меня проблема с использованием Entity Framework TransactionScopes.
Прочитав документацию и просмотрев несколько примеров и предложений, я реализовал области транзакций для многих запросов, которые есть в моем веб-приложении. Проблема, с которой я столкнулся здесь, связана с уровнями изоляции. Я хочу, чтобы каждый запрос в TransactionScope был ReadUncommited, но по какой-то причине только первый запрос должен иметь желаемый уровень изоляции (READ UNCOMMITED), но все последующие запросы возвращаются к READ COMMITED. Эти запросы читают много данных, и я не против грязного чтения.
Это мой EF TransactionScope и Context (очень простой):
var transactionOptions = new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted };
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions, TransactionScopeAsyncFlowOption.Enabled))
{
using (var db = new Context())
{
//db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
//var SessionID = await db.Database.SqlQuery<short>("SELECT @@SPID").FirstOrDefaultAsync();
//db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
//QUERY1
var list1= await db.Table1.Include(x => x.ExternalProperty).Where(x => x.Created >= sevenDaysAgo).ToListAsync();
//QUERY2
var list2 = await db.Table1.Include(x => x.ExternalProperty).Where(x => x.Created >= fourteenDaysAgo && x.Created <= eightDaysAgo).ToListAsync();
//... Doing more stuff here
transactionScope.Complete();
}
}
QUERY 1 выполняется с READ UNCOMMITED, а QUERY 2 по какой-то причине выполняется с READ COMMITED. Я что-то упускаю? Потому что, как я понимаю, этого не должно происходить, поскольку оба запроса имеют один и тот же TransactionScope.
Я использовал await db.Database.SqlQuery<short>("SELECT @@SPID").FirstOrDefaultAsync()
, чтобы получить идентификатор сеанса, зарезервированный контекстом, чтобы убедиться, что используется тот же сеанс.
Я также попытался установить уровень изоляции вручную, используя: db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
, что привело к тому же поведению.
Я поискал и почти все ответы, предлагающие использовать приведенный выше код. Например: ЭТОТ ОТВЕТ
Почему это могло произойти, особенно если TransactionScope еще не завершен?
Спасибо
READ UNCOMMITTED
на самом деле намного хуже - он может пропускать или дублировать строки, если происходит перемещение данных, поэтому ваши результаты не просто потенциально устарели, а совершенно неверны. Не используйте его, если вы не получаете временных результатов, которые все равно будут запрашиваться в ближайшее время (например, в настройках мониторинга). - person Jeroen Mostert   schedule 26.10.2017SELECT
в транзакцию, которая выполняется подREAD UNCOMMITTED
, ничего не делает - нет смысла ни в транзакции, ни в группировке несколькихSELECT
таким образом. Предполагая, что у EF нет другого, более элегантного способа указания уровня изоляции (я не знаю, у меня нет опыта работы с EF), вы также можете выполнить оба оператора в их собственныхTransactionScope
s. Это не повлияет на скорость или правильность, хотя и немного более подробное. - person Jeroen Mostert   schedule 26.10.2017TransactionScope
на запрос (каждый из которых выполняется подREAD UNCOMMITTED
) тривиально решит проблему за счет большего количества кода. - person Jeroen Mostert   schedule 26.10.2017SqlConnection
снова явно установить уровень изоляции из области при включении, возможно, также проблемы с обратной совместимостью. - person Jeroen Mostert   schedule 26.10.2017sp_reset_connection
не сбрасывает уровень изоляции, что на самом деле является именно тем, что вы хотите в этом сценарии (но действительно вызывает проблемы в другом месте). Не уверен, почему он не работает так, как было задумано для этого случая, когда вы действительно хотите, чтобы он работал таким образом. (Если вы не используете старую версию SQL Server 2014, которая включает исправление.) - person Jeroen Mostert   schedule 26.10.2017