У меня возникли проблемы с подавлением части транзакции с использованием Sql Server CE 4 с Entity Framework и System.Transactions.TransactionScope
.Использование TransactionScopeOption.Suppress с Sql Server Compact 4
Упрощенный код, приведенный ниже, относится к единичному тесту, демонстрирующему проблему.
Идея состоит в том, чтобы сделать блок innerScope
(без транзакции) успешным или неудачным, не затрагивая блок outerScope
(транзакция «окружающая»). Это заявленная цель TransactionScopeOption.Suppress
.
Однако код не работает, потому что кажется, что вся таблица SomeTable
заблокирована первой вставкой в outerScope
. В точке, указанной в коде, эта ошибка возникает:
«SQL Server Compact, ожидающий блокировки. Время блокировки по умолчанию составляет 2000 мс для устройств и 5000 мс для настольных компьютеров. Тайм-аут блокировки по умолчанию может быть увеличен в строка сеанса с использованием свойства тайм-аута блокировки ssce: default. [Идентификатор сеанса = 2, Идентификатор потока = 2248, Идентификатор процесса = 13516, Имя таблицы = SomeTable, Тип конфликта = блокировка x (x блоков), Resource = PAG (idx): 1046 ]»
[TestMethod()]
[DeploymentItem("MyLocalDb.sdf")]
public void MyLocalDb_TransactionSuppressed()
{
int count = 0;
// This is the ambient transaction
using (TransactionScope outerScope = new TransactionScope(TransactionScopeOption.Required))
{
using (MyObjectContext outerContext = new MyObjectContext())
{
// Do something in the outer scope
outerContext.Connection.Open();
outerContext.AddToSomeTable(CreateSomeTableRow());
outerContext.SaveChanges();
try
{
// Ambient transaction is suppressed for the inner scope of SQLCE operations
using (TransactionScope innerScope = new TransactionScope(TransactionScopeOption.Suppress))
{
using (MyObjectContext innerContext = new MyObjectContext())
{
innerContext.Connection.Open();
// This insert will work
innerContext.AddToSomeTable(CreateSomeTableRow());
innerContext.SaveChanges(); // ====> EXCEPTION THROWN HERE
// There will be other, possibly failing operations here
}
innerScope.Complete();
}
}
catch { }
}
outerScope.Complete();
}
count = GetCountFromSomeTable();
// The insert in the outer scope should succeed, and the one from the inner scope
Assert.AreEqual(2, count);
}
Таким образом, представляется, что„сделка в области транзакции выполняется с уровнем изоляции, установленным в Сериализуемый“, в соответствии с http://msdn.microsoft.com/en-us/library/ms172001
Однако, используя следующий фрагмент кода, чтобы изменить уровень изоляции TransactionScope не помогает:
public void MyLocalDb_TransactionSuppressed()
{
TransactionOptions opts = new TransactionOptions();
opts.IsolationLevel = IsolationLevel.ReadCommitted;
int count = 0;
// This is the ambient transaction
using (TransactionScope outerScope = new TransactionScope(TransactionScopeOption.Required, opts))
...
То же самое исключение в том же месте.
Кажется, единственный способ избежать этого - позвонить outerScope.Complete()
перед входом в блок innerScope
. Но это победит цель.
Что мне здесь не хватает? Спасибо.
Спасибо за ответ.Но мой пример выше работает отлично, если, например, исходная вставка находится в другой таблице. Если я вставляю в 'SomeOtherTable' в' outerScope', код работает так, как ожидалось. Таким образом, проблема связана с блокировкой на уровне таблицы. – user1425515
Это параллельные транзакции, которые поддерживаются SQLce, но ваш исходный тестовый код создает вложенные файлы, и, как сказал Хосе, они не поддерживаются. – Vanja