我在使用带有实体框架的 Sql Server CE 4 和System.Transactions.TransactionScope
.
下面的简化代码来自演示问题的单元测试。
这个想法是使innerScope
块(没有事务)成功或失败而不影响outerScope
块(“环境”事务)。这是TransactionScopeOption.Suppress
.
但是,代码失败了,因为似乎整个SomeTable
表都被第一次插入锁定了outerScope
。在代码中指示的位置,将引发此错误:
“SQL Server Compact 等待锁定超时。设备的默认锁定时间为 2000 毫秒,桌面为 5000 毫秒。可以使用 ssce:默认锁定超时属性在连接字符串中增加默认锁定超时。[会话 id = 2,线程 id = 2248,进程 id = 13516,表名 = SomeTable,冲突类型 = x 锁(x 块),资源 = 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,似乎“事务范围内的事务在隔离级别设置为 Serializable 的情况下执行”
但是,使用以下代码片段来更改 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))
...
在相同的位置抛出相同的异常。
It seems the only way to avoid this is to call outerScope.Complete()
before entering the innerScope
block. But this would defeat the purpose.
What am I missing here? Thanks.