C# 在一个事务范围内使用EF将数据写入两个数据库

C# 在一个事务范围内使用EF将数据写入两个数据库,c#,entity-framework,transactions,msdtc,C#,Entity Framework,Transactions,Msdtc,我们正在使用实体框架6,并处理以下要求: 我们正在向两个不同且独立的数据库写入数据,我们称之为Main和External,它们都存在于同一个SQL Server实例上,用于连接它们的连接字符串除了初始目录值之外是相同的 在应用程序中,每个DB都有自己的EF DBContext 主数据库有一个AuditLog表,其中记录了数据更改 外部数据库上发生的数据更改需要记录在主数据库内的AuditLog表中 由于某些限制对讨论我们的实现方式并不重要,因此,这是让ExternalContext引用Mai

我们正在使用实体框架6,并处理以下要求:

  • 我们正在向两个不同且独立的数据库写入数据,我们称之为Main和External,它们都存在于同一个SQL Server实例上,用于连接它们的连接字符串除了初始目录值之外是相同的

  • 在应用程序中,每个DB都有自己的EF DBContext

  • 主数据库有一个AuditLog表,其中记录了数据更改

  • 外部数据库上发生的数据更改需要记录在主数据库内的AuditLog表中

由于某些限制对讨论我们的实现方式并不重要,因此,这是让ExternalContext引用MainContext,以便在调用ExternalContext.SubmitChanges时调用MainContext.SaveAuditLogs,如下所示(仅显示相关代码):

为此,需要运行分布式事务协调器服务。在开发环境中测试时,它可以正常工作,但在QA环境中,它会失败并显示错误消息,就好像分布式事务协调器没有运行一样,即使它正在运行

显然,这是因为在我们的开发环境中,DB服务器和Web服务器在QA中是相同的计算机,它们是两个单独的框,当有多个服务器且两个操作在TransactionScope中运行时,DTC不喜欢这样,如果我们删除TransactionScope,那么它在这两种环境中都可以正常工作,但是如果AuditLog失败,则整个事务可能不会回滚

我们怎样才能做到这一点


谢谢。

一个范围对应一个数据库,不是吗?你怎么能在两个人之间共享一个范围?@Steve-除非我弄错了,而且从我在这本书上看到的情况来看,我似乎没有,这个场景就是TransactionScope的用途。看起来我错了。你有没有让它工作过?如果是这样的话,怎么做?一个范围对应一个db,不是吗?你怎么能在两个人之间共享一个范围?@Steve-除非我弄错了,而且从我在这本书上看到的情况来看,我似乎没有,这个场景就是TransactionScope的用途。看起来我错了。你有没有让它工作过?如果是,怎么做?
public class ExternalContext : IDataContext
{
    private readonly IAuditLogContext auditLogContext;

    public ExternalContext (IAuditLogContext auditLogContext){
        this.auditLogContext = auditLogContext;
    }

    public override void SaveChanges()
    {
        base.SaveChanges();
        this.auditLogContext.SaveAuditLogs(auditLogs);
    }
}

public class MainContext : IAuditLogContext
{
    public void SaveAuditLogs(List<AuditLog> auditLogs)
    {
        this.Set<AuditLog>().AddRange(auditLogs);

        this.SaveChanges();
    }
}
public class SomeBusinessClass
{
    private readonly IDataContext dataContext;

    public SomeBusinessClass(IDataContext dataContext)
    {
        this.dataContext = dataContext;
    }

    public void SomeOperation(Entity someEntity)
    {
        .....

        using(var scope = new TransactionScope())
        {
            this.dataContext.Insert(someEntity);
            this.dataContext.SaveChanges();
        }
        scope.Complete();
    }
}