动态 select entity framework 中活动可用数据库的连接字符串

dynamically select the connection string to the actively available database in entity framework

目前,我们正在使用两台具有相同数据库名称和设置的服务器。我想使用活动的连接字符串或我可以轻松连接的连接字符串。例如,有时我们在 server-1 所在的地方停电,所以我可以使用 server-2,因为它位于不同的地方。

在这里,我在 .NET 中使用连接字符串帮助器 class,但没有 entity framework,但我无法为 entity framework.

实现它

在web.config

<add name="dbAdo1a" connectionString="connection for Server-1" providerName="abc" />
<add name="dbAdo1b" connectionString="connection for Server-2" providerName="abc" />

在 C# 中

public class ConnectionStringHelper
    {
        private static readonly Timer Timer;
        private static readonly ConcurrentDictionary<int, string> BestConnectionStrings;
        private const int LoopCount = 3;
        static ConnectionStringHelper()
        {
            BestConnectionStrings = new ConcurrentDictionary<int, string>();
            for (var i = 1; i <= LoopCount; i++)
            {
                GetQuickOneSync(i);
            }
            Timer = new Timer(Constants.ConnectionRefreshTimeout * 1000);
            Timer.Elapsed += async (sender, e) => await HandleTimerElapsed(sender, e).ConfigureAwait(false);
            Timer.AutoReset = false;
            Timer.Start();
        }


        public static string GetConnectionString(int wareHouseId)
        {
            if (!BestConnectionStrings.ContainsKey(wareHouseId))
            {
                return string.Empty;    // just swallow the error if no connection available
            }

            return BestConnectionStrings[wareHouseId];
        }

        private static async Task HandleTimerElapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                // Find the quickies for each of the connection strings
                var sw = new Stopwatch();
                sw.Start();
                // TODO - three sets of ConnectionStrings for now, make dynamic
                for (var i = 1; i <= LoopCount; i++)
                {
                    await GetQuickOne(i).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {

            }
            finally
            {
                Timer.Start();
            }

            async Task GetQuickOne(int wareHouseId)
            {
                var quickone = string.Empty;
                var quickest = long.MaxValue;
                var sw = new Stopwatch();
                for (var c = 'a'; c <= 'z'; c++)
                {
                    var cs = ConfigurationManager.ConnectionStrings[$"dbAdo{wareHouseId}{c}"]?.ConnectionString;
                    if (string.IsNullOrEmpty(cs)) break;
                    sw.Restart();
                    // open connection and see how long it takes
                    using (var connection = new SqlConnection(cs))
                    {
                        try
                        {
                            await connection.OpenAsync().ConfigureAwait(false);
                        }
                        catch (Exception exception)
                        {
                            continue;   // move on
                        }

                        var milliseconds = sw.ElapsedMilliseconds;
                        if (milliseconds < quickest) // quickest so far?
                        {
                            quickest = milliseconds;
                            quickone = cs;
                        }

                        if (milliseconds <= Constants.ConnectionOkThreshold) // is ok if quickest under the threshold, go no further
                        {
                            break;
                        }
                    }
                }

                BestConnectionStrings[wareHouseId] = quickone;
            }
        }

        private static void GetQuickOneSync(int wareHouseId)
        {
            var quickone = string.Empty;
            var quickest = long.MaxValue;
            var sw = new Stopwatch();
            for (var c = 'a'; c <= 'z'; c++)
            {
                var cs = ConfigurationManager.ConnectionStrings[$"dbAdo{wareHouseId}{c}"]?.ConnectionString;
                if (string.IsNullOrEmpty(cs)) break;
                sw.Restart();
                // open connection and see how long it takes
                using (var connection = new SqlConnection(cs))
                {
                    try
                    {
                        connection.Open();
                    }
                    catch (Exception exception)
                    {
                        continue;   // move on
                    }

                    var milliseconds = sw.ElapsedMilliseconds;
                    if (milliseconds < quickest) // quickest so far?
                    {
                        quickest = milliseconds;
                        quickone = cs;
                    }

                    if (milliseconds <= Constants.ConnectionOkThreshold) // is ok if quickest under the threshold, go no further
                    {
                        break;
                    }
                }
            }

            if (!string.IsNullOrEmpty(quickone))
                BestConnectionStrings[wareHouseId] = quickone;
        }
    }

我想使用 System.Data.Entity.DbContext class 为 entity framework 进行同样的设置。我应该能够从 web 配置传递连接字符串的名称并检查它是否有效并且应该重定向到它。

根据您的需要,我可以提出解决方案。我假设您已经为 EF 提供了默认连接字符串。

现在你可以这样做了。

Step-1. 为 EF DB 上下文创建扩展方法:

public 静态 class 连接工具 {

public static void CheckConnection(this DbContext source)
{

    if (!source.Database.Exists())
    {
        //TODO: logic to read all your connection string into a list
        string connectionStrings = new List<string>();
        foreach (var connection in connectionStrings)
        {
            //set new connection and check
            source.Database.Connection.ConnectionString = connection;
            if (source.Database.Exists())
            {
            //break loop
            }
        }
    }
}

}

Step-2. 在调用部分做这样的事情:

-

public void SomeOperation()
{
    //assuming you already have your context injected
    var employees = _context.CheckConnection().Employees.ToList();
}