代码之家  ›  专栏  ›  技术社区  ›  Steve

TransactionScope和DataContext

  •  2
  • Steve  · 技术社区  · 14 年前

    我知道这个问题以前一直在问,但我还没有找到一个真正有效的答案。

    当我的单元测试试图调用使用Linq查询数据库的web服务时,我的问题就出现了。

    单元测试的设置如下:

    [TestInitialize]
    public void SetUp()
    {
        var scope = new TransactionScope(TransactionScopeOption.Required,TimeSpan.MaxValue);
        var database = new DatabaseDataContext();
    }
    
    [TestCleanup]
    public void TearDown()
    {
        scope.Dispose();
        database.Dispose();
    }
    
    [TestMethod]
    public void GetCategoryList_Success()
    {
        // create test data
        var result = service.GetItems();
    }
    

    service.GetItems方法如下所示:

    try
    {
        using (DatabaseDataContext database = new DatabaseDataContext())
        {
            var items = (from i in database.Items
                        select i).ToList<Items>();
            return items;
        }
    }
    catch (Exception ex)
    {
       // log error
       return null;
    }
    

    当Linq查询尝试执行时,将引发以下异常:

    该操作对于事务的状态无效。

    我认为这与嵌套事务有关,但我需要保持测试类中的事务处于打开状态,这样测试数据实际上就不会保存到数据库中,并且我可以在测试运行后处理它。

    另外,我的主机在一个共享实例上,所以我无法直接对服务器进行任何更改。

    有没有办法让它按原样工作,或者,有没有办法在这个上下文中使用TransactionScope?

    1 回复  |  直到 14 年前
        1
  •  0
  •   VladV    14 年前

    您正试图在单个TransactionScope中创建到同一数据库的两个连接—一个用于测试进程,另一个用于web服务进程。这不起作用,因为来自不同进程的数据库传输显然不能嵌套。

    你应该改变你的测试方法。读简的答案。

    作为解决方法,您可以让您的web服务管理事务。一种方法,比如说, BeginGlobalTran 如果要为web服务(存储在属性中)创建全局事务(或TransactionScope)对象,则其所有其他方法都应使用此对象(因此,所有其他事务都嵌套在“全局”事务中),另一个方法是, RollbackGlobalTran 应该回滚此“全局”事务。
    这就是说,这是一种解决方法,可能会导致一些意外的副作用(例如,方法中的错误将使“全局”事务不可跟踪,因此必须重新启动它以避免进一步的错误)。