繁体   English   中英

如何在一次交易中获得两个单位的工作

[英]How can I get two units of work under a single transaction

我有一个包含两个数据库的MS Sql Server。 在C#控制台应用程序中,我创建了两个不同的实体数据模型(edmx)(EF6); 一个用于DatabaseA,一个用于DatabaseB; 将存储库和工作单元应用于两者。 另外,它们运作良好。 没问题。 我无法弄清楚的是如何将两者都置于一个“交易”之下。

在EF之前,我将创建SqlConnection和SqlTransaction,修改该事务中任一数据库中的相关表,然后根据需要提交或回滚。 但这似乎没有EF中的模拟。

UnitOfWorkForDatabaseA.Commit(); 
UnitOfWorkForDatabaseB.Commit(); //If this fails, both should rollback

但是,使用两个独立的工作单元,每个工作单元都有自己的ObjectContext,这似乎是不可能的。

我是否需要在TransactionScope中将它们包围起来? 或者设计一个SuperUnitOfWork?

使用TransactionScope和分布式事务(警告需要MSDTC),或者对两个DbContext实例使用单个SqlConnection。 您必须通过调用手动将数据库上下文从第一个数据库切换到第二个数据库

USE OtherDatabaseName

要使这项工作最简单的方法是使用TransactionScope(因为你使用的是单个SqlConnection,它不会被提升为DTC事务)。

例如

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;

namespace ConsoleApp8
{

    public class A
    {
        public int AID { get; set; }
        public string Name { get; set; }
    }

    public class B
    {

        public int BId { get; set; }
        public string Name { get; set; }
    }
    class DbA : DbContext
    {
        public DbA(): base()
        {

        }
        public DbA(DbConnection con) : base(con,false)
        {

        }
        public DbSet<A> A { get; set; }


    }
    class DbB : DbContext
    {
        public DbB() : base()
        {

        }
        public DbB(DbConnection con) : base(con, false)
        {

        }
        public DbSet<B> B { get; set; }


    }



    class Program
    {      

        static void Main(string[] args)
        {

            Database.SetInitializer(new CreateDatabaseIfNotExists<DbA>());
            Database.SetInitializer(new CreateDatabaseIfNotExists<DbB>());
            string DatabaseNameA, DatabaseNameB;
            using (var db = new DbA())
            {
                db.Database.Initialize(false);
                DatabaseNameA = db.Database.Connection.Database;
            }

            using (var db = new DbB())
            {
                db.Database.Initialize(false);
                DatabaseNameB = db.Database.Connection.Database;
            }

            var opts = new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted };

            using (var dbA = new DbA())
            using (var tran = new TransactionScope(TransactionScopeOption.Required, opts))
            {


                var a = dbA.A.Create();
                a.Name = "someA";
                dbA.A.Add(a);
                dbA.SaveChanges();

                dbA.Database.ExecuteSqlCommand($"use [{DatabaseNameB}]");
                using (var dbB = new DbB(dbA.Database.Connection))
                {

                    var b = dbB.B.Create();
                    b.Name = "someB";
                    dbB.B.Add(b);
                    dbB.SaveChanges();

                }

                tran.Dispose();

            }



            using (var dbA = new DbA())
            {
                dbA.Database.Connection.Open(); //lock the connection open if not using a transaction
                Console.WriteLine($"Count of A: {dbA.A.Count()}");

                dbA.Database.ExecuteSqlCommand($"use [{DatabaseNameB}]");
                using (var dbB = new DbB(dbA.Database.Connection))
                {
                    Console.WriteLine($"Count of B: {dbB.B.Count()}");

                }



            }

            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();






        }
    }
}

输出

Count of A: 0
Count of B: 0
Hit any key to exit

你必须在这里使用TransactionScope的原因是SaveChanges将在内部使用SqlTransaction。 有趣的事实:SqlTransaction非常糟糕。 它需要手动SqlCommand登记,并且它不支持嵌套事务(它称之为“并行事务”)。 它的任何方式都是从.NET 1.0开始的,并且无法真正改变。 但是当它出现在.NET 2.0中时,它可以与System.Transactions一起正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM