实体框架:使用事务和回滚......可能吗?

Pro*_*ool 18 entity-framework transactions

问题:(使用Sql 2005)

  • 如何在事务处理时查询数据库?(因为它锁定表)
  • 如何导致事务回滚然后关闭自己以允许查询表?

所以我发现了这么多:

[TestMethod]
public void CreateUser()
{
    TransactionScope transactionScope = new TransactionScope();

    DataContextHandler.Context.AddToForumUser(userToTest);
    DataContextHandler.Context.SaveChanges();

    DataContextHandler.Context.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

更新这适用于回滚和检查,但仍然无法在使用部分内查询:

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);
Run Code Online (Sandbox Code Playgroud)

Jer*_*ink 15

来自MSDN ;

"SaveChanges在一个事务中运行.如果任何脏的ObjectStateEntry对象无法持久化,SaveChanges将回滚该事务并抛出异常."

所以似乎没有必要明确添加自己的事务处理TransactionScope.

  • 我不认为这是OP关注的背景.他希望能够在测试后回滚数据库,但能够在测试期间查询它. (4认同)

小智 7

在我的情况下,我通过纯SQL删除表中的所有记录,因为EF不提供此功能.之后我添加了一些新实体 - 但是当它失败时,表不应该是空的.我不可能使用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;
      }
}
Run Code Online (Sandbox Code Playgroud)

这里是辅助函数

    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;
    }
Run Code Online (Sandbox Code Playgroud)


Vik*_*orZ 5

我已经能够使用此代码片段解决非常类似的问题:

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();
}
Run Code Online (Sandbox Code Playgroud)

MyEntitiesEF DataModel 在哪里.关键部分是交易的设定:System.Data.IsolationLevel.ReadUncommitted.
使用此隔离级别SQL查询可以读取事务内部所做的更改.您还需要像我在第一行和第二行那样显式创建连接.TransactionScope不幸的是,我无法使用它.

  • @TheIndianProgrammmer你能解释一下原因吗? (3认同)
  • @TheIndianProgrammmer回滚绝对是在finally块中故意,因为无论发生什么,我都想执行它.请检查初始问题和整个答案,而不仅仅是代码. (3认同)