事务范围和数据上下文
我意识到这个问题以前就有人问过,但我还没有找到真正有效的答案。
当我的单元测试尝试调用使用 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 的替代方法?
I realise this question has been asking before, but I've yet to find an answer that actually works.
My issue is occuring when my unit tests are trying to call a web service that uses Linq to query the database.
The unit test is set up like so:
[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();
}
The service.GetItems method looks like so:
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;
}
When the Linq query tries to execute, the following exception is thrown:
The operation is not valid for the state of the transaction.
I believe this is to do with nested transactions, but I need to keep the transaction in the test class open so that the test data is not actually saved to the database and I can dispose of it once the test is run.
Also, my hosting is on a shared instance, so I am unable to make any changes to the server directly.
Is there a way to get this to work as is, or alternatively, is there an alternative to using TransactionScope in this context?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正尝试在单个 TransactionScope 内创建到同一数据库的两个连接 - 一个连接用于测试进程,另一个连接用于 Web 服务进程。这是行不通的,因为在数据库中,来自不同进程的事务显然不能嵌套。
您应该在此处更改测试方法。阅读简的回答。
作为解决方法,您可以让您的 Web 服务管理事务。一个方法,比如
BeginGlobalTran
应该为 Web 服务创建一个全局 Transaction(或 TransactionScope)对象(存储在属性中),它的所有其他方法都应该使用这个对象(因此,所有其他事务都嵌套在“全局”事务),另一种方法是,RollbackGlobalTran
应该回滚这个“全局”事务。话虽这么说,这是一种解决方法,可能会导致一些意外的副作用(例如,该方法中的错误将使“全局”事务无法提交,因此您必须重新启动它以避免进一步的错误)。
You are trying to create two connections to the same database within a single TransactionScope - one connection for the test process, and another one for the web service process. This doesn't work because in the database tranasctions from different processes obviously can't be nested.
You should change your approach to testing here. Read Jan's answer.
As a workaround, you could make your web service manage the transaction. A method, say,
BeginGlobalTran
should create a global Transaction (or TransactionScope) object for the web service (stored in property), all other its methods should use this object (so, all other transactions are nested within the 'global' transaction), another method say,RollbackGlobalTran
should rollback this 'global' transaction.That being said, it is a workaround and it might cause some unexpected side-effects (for instance, an error in the method will make the 'global' transaction uncommitable, so you will have to restart it to avoid further errors).