Sql Server CE 4 と Entity Framework およびSystem.Transactions.TransactionScope
.
以下の単純化されたコードは、問題を示す単体テストからのものです。
アイデアは、ブロック (「周囲の」トランザクション)innerScope
に影響を与えることなく、ブロック (トランザクションなし) が成功または失敗できるようにすることです。outerScope
これが の目的ですTransactionScopeOption.Suppress
。
SomeTable
ただし、 への最初の挿入によってテーブル全体がロックされているように見えるため、コードは失敗しますouterScope
。コードに示されている時点で、次のエラーがスローされます。
"SQL Server Compact がロックの待機中にタイムアウトしました。既定のロック時間は、デバイスの場合は 2000 ミリ秒、デスクトップの場合は 5000 ミリ秒です。既定のロック タイムアウトは、接続文字列で ssce: default lock timeout プロパティを使用して増やすことができます。[セッション 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))
...
同じ場所で同じ例外がスローされます。
これを回避する唯一の方法は、ブロックouterScope.Complete()
に入る前に呼び出すことです。innerScope
しかし、これは目的に反します。
ここで何が欠けていますか?ありがとう。