問題:(SQL 2005を使用)
だから私はこれをたくさん見つけました:
[TestMethod]
public void CreateUser()
{
TransactionScope transactionScope = new TransactionScope();
DataContextHandler.Context.AddToForumUser(userToTest);
DataContextHandler.Context.SaveChanges();
DataContextHandler.Context.Dispose();
}
ここで、DataContextHandlerは、エンティティのコンテキストオブジェクトを公開する単純なシングルトンです。これはあなたが思うようにうまくいくようです。ユーザーを作成して保存し、プログラムの終了時にロールバックします。 (IEテスト終了)
問題:テーブルをクエリできるように、トランザクションを強制的にロールバックして強制終了するにはどうすればよいですか?
理由:テストの目的で、ユーザーが次のことを確認したいと思います。
現在のところ、テストが終了した場合にのみトランザクションをロールバックすることができ、トランザクションを上げてクエリを実行する方法がわかりません。
[TestMethod]
public void CreateUser()
{
ForumUser userToTest = new ForumUser();
TransactionScope transactionScope = new TransactionScope();
DataContextHandler.Context.AddToForumUser(userToTest);
DataContextHandler.Context.SaveChanges();
Assert.IsTrue(userToTest.UserID > 0);
var foundUser = (from user in DataContextHandler.Context.ForumUser
where user.UserID == userToTest.UserID
select user).Count(); //KABOOM Can't query since the
//transaction has the table locked.
Assert.IsTrue(foundUser == 1);
DataContextHandler.Context.Dispose();
var after = (from user in DataContextHandler.Context.ForumUser
where user.UserID == userToTest.UserID
select user).Count(); //KABOOM Can't query since the
//transaction has the table locked.
Assert.IsTrue(after == 0);
}
PDATEこれはロールバックとチェックで機能しましたが、usingセクション内でクエリを実行できません:
using(TransactionScope transactionScope = new TransactionScope())
{
DataContextHandler.Context.AddToForumUser(userToTest);
DataContextHandler.Context.SaveChanges();
Assert.IsTrue(userToTest.UserID > 0);
//Still can't query here.
}
var after = (from user in DataContextHandler.Context.ForumUser
where user.UserID == userToTest.UserID
select user).Count();
Assert.IsTrue(after == 0);
から [〜#〜] msdn [〜#〜] ;
「SaveChangesはトランザクション内で動作します。ダーティなObjectStateEntryオブジェクトのいずれかを永続化できない場合、SaveChangesはそのトランザクションをロールバックし、例外をスローします。」
したがって、TransactionScope
を介して独自のトランザクション処理を明示的に追加する必要はないようです。
私の場合、EFはこの機能を提供していないため、プレーンSQLを使用してテーブルからすべてのレコードを削除します。その後、いくつかの新しいエンティティを追加しますが、失敗した場合、テーブルは空であってはなりません。 MSDTC(TransactionScope)の使用は私には不可能のようです。トランザクションをDBに減らしました:
私のコード:
using (var transaction = context.Connection.BeginTransaction())
{
// delete all
base.DeleteAll<TESTEntity>(context);
// add all
foreach (var item in items)
{
context.TESTEntity.AddObject(item);
}
try
{
context.SaveChanges();
transaction.Commit();
return true;
}
catch (Exception ex)
{
Logger.Write("Error in Save: " + ex, "Error");
transaction.Rollback();
return false;
}
}
そしてここでヘルパーは機能します
protected void DeleteAll<TEntity>(ObjectContext context) where TEntity : class
{
string tableName = GetTableName<TEntity>(context);
int rc = context.ExecuteStoreCommand(string.Format(CultureInfo.InvariantCulture, "DELETE FROM {0}", tableName));
}
protected string GetTableName<TEntity>(ObjectContext context) where TEntity : class
{
string snippet = "FROM [dbo].[";
string sql = context.CreateObjectSet<TEntity>().ToTraceString();
string sqlFirstPart = sql.Substring(sql.IndexOf(snippet) + snippet.Length);
string tableName = sqlFirstPart.Substring(0, sqlFirstPart.IndexOf("]"));
return tableName;
}
私はこのコードフラグメントを使用して非常に類似した問題を解決することができました:
var connection = new EntityConnection("name=MyEntities");
connection.Open();
var tran = connection.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
try
{
var dataContext = new MyEntities(connection);
//CRUD operation1
//CRUD operation2
//CRUD operation3 ...
Assert.AreEqual(expected, actual);
}
catch
{
throw;
}
finally
{
tran.Rollback();
connection.Close();
}
ここで、MyEntities
はEFDataModelです。重要な部分は、トランザクションの設定です:System.Data.IsolationLevel.ReadUncommitted
。
この分離レベルを使用すると、SQLクエリでトランザクション内で行われた変更を読み取ることができます。また、1行目と2行目で行うように、明示的に接続を作成する必要があります。残念ながら、TransactionScope
を使用して動作させることはできませんでした。