Entity framework 使用实体框架从一个数据库故障切换到另一个数据库的通用模式?

Entity framework 使用实体框架从一个数据库故障切换到另一个数据库的通用模式?,entity-framework,database-design,Entity Framework,Database Design,我们有一个企业数据库,可以通过世界各地的许多站点进行复制。我们希望我们的应用程序尝试连接到一个本地站点,如果该站点关闭,我们希望它返回到企业数据库。我们希望每个DB操作都有这种行为 我们正在使用实体框架、C#和SQL Server 起初,我希望可以在连接字符串中指定一个“故障转移伙伴”,但这只适用于镜像数据库环境,而事实并非如此。我还研究了如何编写自定义的IDB执行策略。但是这些策略只允许您指定重试失败的DB操作的模式。它不允许您以任何方式更改操作,就像将其定向到新连接一样 那么,除了围绕我们的

我们有一个企业数据库,可以通过世界各地的许多站点进行复制。我们希望我们的应用程序尝试连接到一个本地站点,如果该站点关闭,我们希望它返回到企业数据库。我们希望每个DB操作都有这种行为

我们正在使用实体框架、C#和SQL Server

起初,我希望可以在连接字符串中指定一个“故障转移伙伴”,但这只适用于镜像数据库环境,而事实并非如此。我还研究了如何编写自定义的IDB执行策略。但是这些策略只允许您指定重试失败的DB操作的模式。它不允许您以任何方式更改操作,就像将其定向到新连接一样

那么,除了围绕我们的许多DB操作中的每一个复制重试逻辑之外,您知道处理这种类型的操作有什么好的模式吗


2014年5月14日更新:

我将详细阐述对已经提出的一些建议的回应

我有很多地方的代码是这样的:

try
{
    using(var db = new MyDBContext(ConnectionString))
    {
        // Database operations here.
        // var myList = db.MyTable.Select(...), etc.
    }
}
catch(Exception ex)
{
    // Log exception here, perhaps rethrow.
}
有人建议我有一个例程,首先检查每个连接字符串并返回第一个成功连接的字符串。就目前而言,这是合理的。但我看到的一些错误是操作超时,连接正常,但DB存在问题,无法完成操作


我要寻找的是一种模式,我可以用它来封装工作单元,并说,“在第一个数据库上尝试这个方法。如果它因任何原因失败,请回滚并在第二个数据库上尝试它。如果失败,请在第三个数据库上尝试它,以此类推,直到操作成功,或者您没有更多的数据库。”我非常确定我可以自己启动数据库(如果有,我会发布结果),但我希望有一种已知的方法来解决这个问题。

使用一些依赖项注入系统(如autofac)并在那里注册一个新上下文对象的工厂如何?它将执行逻辑,尝试首先连接到本地,如果失败,它将连接到企业数据库。然后它将返回ready DbContext obje这个工厂将通过依赖注入系统提供给所有需要它的对象-他们将使用它来创建上下文,并在不再需要它们时处理它们。

“我们希望我们的应用程序尝试连接到其中一个本地站点,如果该站点关闭,我们希望它返回到企业数据库。我们希望在每个数据库操作中都出现这种行为。”

如果你的应用程序在数据库上是只读的,并且数据一致性对你的应用程序/用户来说不是绝对重要的,那么这只是一个尝试连接的问题,直到找到一个可操作的站点。正如M.Ali在他的评论中所建议的


否则,我建议你立即停止沿着这些思路思考,因为你只是在一条死胡同上以90英里/小时的速度行驶。正如维克多·齐奇拉在他的评论中所建议的那样。

以下是我最终实现的目标,简单地说:

定义名为UnitOfWorkMethod的委托,该委托将在单个事务中对数据库执行单个工作单元。它接受一个连接字符串,还返回一个值:

delegate T UnitOfWorkMethod<out T>(string connectionString);
delegate void UnitOfWorkMethod(string connectionString);
调用ExecuteOW时,它会在每个数据库上尝试委托,直到在所有数据库上成功或失败为止

我将接受这个答案,因为它完全解决了原始问题中提出的所有问题。但是,如果有人提供了更优雅、更容易理解的答案,或者纠正了这个问题中的缺陷,我将乐意接受它


感谢所有回应者。

我可以要求将其移至dba.stackexchange.com,但我真的认为这更多的是一个编程/实体框架问题,而不是数据库管理问题。我错了吗?是的,我可以看到。忽略我之前的陈述:)那么,交易的方法是什么?如果事务中的一个失败的操作在事务的中间切换到后退数据库?这里可能是错误的,但是我认为这通常属于负载均衡器的权限。它不是简单的1)打开连接到一个你想要连接的数据库第一。Action.State property if connects is open/builded good if not open connection to your enterprise db?感谢您的回复。我同意,如果我关心跨多个工作单元的事务,我所寻求的将不实用。我还同意我可以在每个UOW周围放置包装逻辑以尝试连接,然后使用Works。但我想说的不止这些,而且我希望避免在每个UOW中重复这个逻辑。我将更新原始问题以进行详细说明。感谢您的回答。这可能是我寻求的开始,但我正在寻找能够处理操作过程中失败的东西。我更新了问题以澄清问题.
protected T ExecuteUOW<T>(UnitOfWorkMethod<T> method)
{
    // GET THE LIST OF CONNECTION STRINGS
    IEnumerable<string> connectionStringList = ConnectionStringProvider.GetConnectionStringList();

    // WHILE THERE ARE STILL DATABASES TO TRY, AND WE HAVEN'T DEFINITIVELY SUCCEDED OR FAILED
    var uowState = UOWStateEnum.InProcess;
    IEnumerator<string> stringIterator = connectionStringList.GetEnumerator();
    T returnVal = default(T);
    Exception lastException = null;
    string connectionString = null;
    while ((uowState == UOWStateEnum.InProcess) && stringIterator.MoveNext())
    {
        try
        {
            // TRY TO EXECUTE THE UNIT OF WORK AGAINST THE DB.
            connectionString = stringIterator.Current;
            returnVal = method(connectionString);
            uowState = UOWStateEnum.Success;
        }
        catch (Exception ex)
        {
            lastException = ex;
            // IF IT FAILED BECAUSE OF A TRANSIENT EXCEPTION,
            if (TransientChecker.IsTransient(ex))
            {
                // LOG THE EXCEPTION AND TRY AGAINST ANOTHER DB.
                Log.TransientDBException(ex, connectionString);
            }
                // ELSE
            else
            {
                // CONSIDER THE UOW FAILED.
                uowState = UOWStateEnum.Failed;
            }
        }
    }

    // LOG THE FAILURE IF WE HAVE NOT SUCCEEDED.
    if (uowState != UOWStateEnum.Success)
    {
        Log.ExceptionDuringDataAccess(lastException);
        returnVal = default(T);
    }
    return returnVal;
}
UnitOfWorkMethod uowMethod =
    (providerConnectionString =>
     {
         using (var db = new MyContext(providerConnectionString ))
         {
             // Do my DB commands here.  They will roll back if exception thrown.
         }
     });
ExecuteUOW(uowMethod);