一个事务与多个dbcontexts [英] One transaction with multiple dbcontexts

查看:228
本文介绍了一个事务与多个dbcontexts的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用我的单元测试事务回滚的变化。单元测试使用的DbContext,我测试服务使用自己的。两者都包裹在一个事务中,一个的DbContext是在其它的块。问题是,当内部的DbContext节省了他的变化,这是不可见的外部的DbContext(我不认为这是因为其他的DbContext可能已经加载的对象)。下面是例子:

I am using transactions in my unit tests to roll back changes. The unit test uses a dbcontext, and the service i'm testing uses his own. Both of them are wrapped in one transaction, and one dbcontext is in the block of the other. The thing is, when the inner dbcontext saves his changes, it's not visible to the outer dbcontext (and i don't think it's because the other dbcontext might already have the object loaded). Here is the example:

[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,一切工作正常:

However, if I close the outer dbcontext before calling the service and open a new dbcontext for the assert, everything works fine:

[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嵌套。 难道使用(的DbContext)就像是一个事务本身来监守?如果是这样,我还是不明白的问题,因为我打电话.SaveChanges()在内的DbContext。

So basically i have a solution for this problem (thought of it during the writing of this question) but i still wonder why it isn't possible accessing uncommitted data in the transaction when the dbcontexts are nested. Could it be becuase using(dbcontext) is like a transaction itself? If so, i still don't understand the issue since i'm calling .SaveChanges() on the inner dbcontext.

推荐答案

在第一种情况下,你嵌套 DbContexts 。打开每个他们到数据库的连接。当你调用使用块中的服务方法,是在打开一个新的连接的TransactionScope 同时有另外一个已经打开。这将导致您的交易被提拔到 分布式事务 < /一>,和部分提交的数据(在服务 DbContext.SaveChanges 调用的结果)不是可从外部连接。还要注意的是分布式事务是慢得多,因此,这具有降低性能的副作用

In the first scenario, you are nesting DbContexts. A connection to the database is opened for each on of them. When you call your service method within the using block, a new connection is opened within the TransactionScope while there is another one already open. This causes your transaction to be promoted to a distributed transaction, and partially committed data (the result of the DbContext.SaveChanges call in the service) not being available from your outer connection. Also note that distributed transactions are far slower and thus, this has the side effect of degrading performance.

在第二个方案中,当你打开和关闭三种连接方式,只有一个连接在你的事务中同时打开。由于这些连接共享的相同的连接字符串,该交易将不会自动提升为分布式连接,因此,本次交易中的每个后续连接访问由previous连接进行修改

In the second scenario, while you open and close three connections, only one connection is open at the same time within your transaction. Since these connections share the same connection string, the transaction won't be automatically promoted to a distributed connection and thus, each subsequent connection within the transaction has access to the changes performed by the previous connection.

您可以尝试添加招募=假参数来连接字符串。这将禁用自动争取在分布式事务,从而导致一个例外,在你的第一个方案被提出。第二种情况将保持完美的工作,如果你使用的是SQL Server 2008和超越,因为该交易将不会得到提拔。 (<一href="http://jeffmlakar.word$p$pss.com/2011/12/07/differences-in-escalation-to-distributed-transaction-coordinator-starting-in-sql-server-2008/"相对=的SQL Servernofollow的>以前的版本仍然会推动此方案中的交易。

You may try adding the Enlist=false parameter to your connection string. This would disable automatic enlisting in a distributed transaction, causing an exception to be raised in your first scenario. The second scenario would keep working flawlessly if you are using SQL Server 2008 and beyond, since the transaction won't get promoted. (Prior versions of SQL Server will still promote the transaction in this scenario.)

您也可以找到有用的 以一个非常类似的问题,这个伟大的答案。

You may also find helpful this great answer to a quite similar question.

这篇关于一个事务与多个dbcontexts的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆