Mar*_*uer 6 database-design entity-framework
我们有一个企业数据库,可以通过世界各地的许多站点进行复制.我们希望我们的应用程序尝试连接到其中一个本地站点,如果该站点关闭,我们希望它回退到企业数据库.我们在每个数据库操作上都喜欢这种行为.
我们正在使用Entity Framework,C#和SQL Server.
起初我希望我可以在连接字符串中指定一个"故障转移伙伴",但这只适用于镜像数据库环境,而不是这样.我还研究了编写自定义IDbExecutionStrategy.但是这些策略仅允许您指定重试失败的数据库操作的模式.它不允许您以任何方式更改操作,例如将其指向新连接.
那么,除了在我们的许多数据库操作中复制重试逻辑之外,您是否知道处理此类操作的任何良好模式?
2014-05-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.
}
Run Code Online (Sandbox Code Playgroud)
有人建议我有一个例程,首先检查每个连接字符串并返回第一个成功连接的连接字符串.这是合理的.但是我看到的一些错误是操作超时,连接工作但DB有问题阻止它完成操作.
我正在寻找的是一种模式,我可以用来封装工作单元,然后说:"在第一个数据库上尝试这个.如果因任何原因失败,请回滚并在第二个数据库上尝试.如果失败,请尝试它在第三个等等,直到操作成功或你没有更多的数据库." 我很确定我可以自己滚动(如果我这样做,我会发布结果),但我希望可能有一种已知的方法来解决这个问题.
以下是我最终实现的大致内容:
定义名为 UnitOfWorkMethod 的委托,它将在单个事务中在数据库上执行单个工作单元。它需要一个连接字符串,并且还返回一个值:
delegate T UnitOfWorkMethod<out T>(string connectionString);
delegate void UnitOfWorkMethod(string connectionString);
Run Code Online (Sandbox Code Playgroud)
定义一个名为 ExecuteUOW 的方法,该方法将采用一个工作单元,并且方法尝试使用首选连接字符串来执行它。如果失败,它会尝试使用下一个连接字符串执行它:
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;
}
Run Code Online (Sandbox Code Playgroud)
最后,对于每个操作,我们定义工作单元委托方法。这是一个例子
UnitOfWorkMethod uowMethod =
(providerConnectionString =>
{
using (var db = new MyContext(providerConnectionString ))
{
// Do my DB commands here. They will roll back if exception thrown.
}
});
ExecuteUOW(uowMethod);
Run Code Online (Sandbox Code Playgroud)
调用 ExecuteUOW 时,它会在每个数据库上尝试委托,直到在所有数据库上成功或失败。
我将接受这个答案,因为它完全解决了原始问题中提出的所有问题。然而,如果有人提供和回答更优雅、更容易理解,或者纠正这个问题中的缺陷,我会很乐意接受。
感谢所有回复的人。
| 归档时间: |
|
| 查看次数: |
905 次 |
| 最近记录: |