c# – 一个具有多个dbcontex的事务

前端之家收集整理的这篇文章主要介绍了c# – 一个具有多个dbcontex的事务前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我在单元测试中使用交易来回滚更改.单元测试使用dbcontext,我正在测试的服务使用自己的.它们都包裹在一个事务中,一个dbcontext在另一个事务的块中.事情是,当内部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,newCode);

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

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

解决方法

在第一种情况下,您正在嵌套DbContexts.打开与数据库的连接.当您在使用块中调用服务方法时,将在另一个已经打开的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#相关文章