gpt4 book ai didi

c# - 具有多个 dbcontext 的一个事务

转载 作者:可可西里 更新时间:2023-11-01 02:59:59 25 4
gpt4 key购买 nike

我在单元测试中使用事务来回滚更改。单元测试使用 dbcontext,而我正在测试的服务使用他自己的。它们都包含在一个事务中,一个 dbcontext 在另一个的 block 中。问题是,当内部 dbcontext 保存他的更改时,它对外部 dbcontext 不可见(我不认为这是因为另一个 dbcontext 可能已经加载了对象)。这是示例:

[TestMethod]
public void EditDepartmentTest()
{
using (TransactionScope transaction = new TransactionScope())
{
using (MyDbContext db = new MyDbContext())
{
//Arrange
int departmentId = (from d in db.Departments
where d.Name == "Dep1"
select d.Id).Single();
string newName = "newName",
newCode = "newCode";

//Act
IDepartmentService service = new DepartmentService();
service.EditDepartment(departmentId, newName, newCode);

//Assert
Department department = db.Departments.Find(departmentId);
Assert.AreEqual(newName, department.Name,"Unexpected department name!");
//Exception is thrown because department.Name is "Dep1" instead of "newName"
Assert.AreEqual(newCode, department.Code, "Unexpected department code!");
}
}
}

服务:

public class DepartmentService : IDepartmentService
{
public void EditDepartment(int DepartmentId, string Name, string Code)
{
using (MyDbContext db = new MyDbContext ())
{
Department department = db.Departments.Find(DepartmentId);

department.Name = Name;
department.Code = Code;

db.SaveChanges();

}
}
}

但是,如果我在调用服务之前关闭外部 dbcontext 并为断言打开一个新的 dbcontext,一切正常:

[TestMethod]
public void EditDepartmentTest()
{
using (TransactionScope transaction = new TransactionScope())
{
int departmentId=0;
string newName = "newName",
newCode = "newCode";

using (MyDbContext db = new MyDbContext())
{
//Arrange
departmentId = (from d in db.Departments
where d.Name == "Dep1"
select d.Id).Single();
}

//Act
IDepartmentService service = new DepartmentService();
service.EditDepartment(departmentId, newName, newCode);

using (MyDbContext db = new MyDbContext())
{
//Assert
Department department = db.Departments.Find(departmentId);
Assert.AreEqual(newName, department.Name,"Unexpected department name!");
Assert.AreEqual(newCode, department.Code, "Unexpected department code!");
}
}
}

所以基本上我有一个解决这个问题的方法(在写这个问题的时候想到了)但是我仍然想知道为什么当 dbcontexts 嵌套时无法访问事务中未提交的数据。可能是因为 using(dbcontext) 就像事务本身一样吗?如果是这样,我仍然不明白这个问题,因为我在内部 dbcontext 上调用 .SaveChanges()。

最佳答案

在第一个场景中,您嵌套了 DbContexts。为它们中的每一个打开到数据库的连接。当您在 using block 中调用您的服务方法时,将在 TransactionScope 中打开一个新连接,而另一个连接已经打开。这会导致您的交易被提升为 distributed transaction ,并且部分提交的数据(服务中 DbContext.SaveChanges 调用的结果)无法从您的外部连接获得。另请注意,分布式事务要慢得多,因此会产生性能下降的副作用。

在第二种情况下,当您打开和关闭三个连接时,您的事务中同时只打开一个连接。由于这些连接共享相同的连接字符串,事务不会自动提升为分布式连接,因此事务中的每个后续连接都可以访问前一个连接执行的更改。

您可以尝试将 Enlist=false 参数添加到您的连接字符串中。这将禁用分布式事务中的自动登记,导致在您的第一个场景中引发异常。如果您使用的是 SQL Server 2008 及更高版本,第二种情况将继续完美运行,因为事务不会得到提升。 ( Prior versions of SQL Server will still promote the transaction in this scenario. )

您可能还会发现有帮助 this great answer一个非常相似的问题。

关于c# - 具有多个 dbcontext 的一个事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21202982/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com