有没有办法轻松地将大量依赖 SqlConnection 的代码切换到 MySqlConnection

Posted

技术标签:

【中文标题】有没有办法轻松地将大量依赖 SqlConnection 的代码切换到 MySqlConnection【英文标题】:Is there a way to easily switch a lot of code dependent on SqlConnection to MySqlConnection 【发布时间】:2019-06-30 06:02:34 【问题描述】:

我有一个包含超过 200,000 行代码的旧应用程序。

它目前使用 MS Sql Express 作为其数据存储。调用了存储过程,CURD 功能主要通过表适配器实现。

由于 SqlExpress 有 10 GB 的限制,我正在尝试将应用程序更改为使用 mysql 数据库。

我使用mysql workbench自带的迁移向导来导入所有数据。

现在是我面临的问题。

在当前代码中,有一个单例连接管理器是这样访问的

var connection = ConnectionManager.GetInstance().GetNewSQLConnection();
            if (connection.State == ConnectionState.Closed) connection.Open();
            int? iErrorNumber = 0;
            DataTable dt;
            string sErrorMessage = "";
            try
            
                SqlParameter[] paramsToStore = new SqlParameter[3];
                paramsToStore[0] = new SqlParameter("@iErrorNumber", SqlDbType.Int);
                paramsToStore[0].Value = iErrorNumber;
                paramsToStore[1] = new SqlParameter("@sErrorMessage", SqlDbType.NVarChar);
                paramsToStore[1].Size = 8000;
                paramsToStore[1].Value = sErrorMessage;
                paramsToStore[2] = new SqlParameter("@iAssayPK", iAssayPK);
                dt = SqlHelper.ExecuteDataset(connection, CommandType.StoredProcedure, "USP_ASY_AssayUseCount", paramsToStore).Tables[0];
            

这是 ConnectionManager 的提取接口

public interface IConnectionManager
    
        string GenerateDBUsername(string _sDatabase, string _sUsername);
        Connection GetConnection();
        Connection GetCurrentConnection();
        SqlConnection GetNewSQLConnection();
        string GetOrmConnectionString();
        void SetCurrentConnection(Connection _oConCurrentConnection);
        void UpdateConnection(Connection _oTheConnection, bool _bSavePassword, string _sNameBeforeUpdate, string ServerAddress);
    

如您所见,GetNewSQLConnection() 返回一个 SqlConnection 对象。 有数百个地方使用了这种连接。 并且大多数时候它都像这样传递给 tableAdapter

using (CustomNamesTableAdapter tadaCustomNames = new CustomNamesTableAdapter())
            
                try
                
                    tadaCustomNames.Connection = ConnectionManager.GetInstance().GetNewSQLConnection();
                    tadaCustomNames.Fill(_dtblToFill, ref iErrorNumber, ref sErrorMessage);
                    if (iErrorNumber != 0)
                    
                        ErrorLogManager.GetInstance().WriteDBError(DateTime.Now, (int)iErrorNumber, sErrorMessage, "USP_CSN_GetCustomNames", this.GetType().ToString(), "void GetCustomerNames(CommonDataSet.CustomNamesDataTable _dtblToFill)", "Error while executing SP");
                        throw new BDRException(Globals.BDRMessageType.EXCEPTION, DateTime.Now, 46, "Error while executing SP");
                    
                

我想如果我可以继承 SqlConnection 类,我就可以创建一个类,也许我可以尝试将 SqlConnection 和 MySqlConneciton 组合成一个对象,并根据所选的当前数据库使用基础对象。

但我正在查看的表适配器也使用 System.Data.SqlClient 中的其他类型,例如参数,并且尝试更新所有代码将意味着更改代码很多地方....

我知道如果应用程序是使用 ORM 构建的,这将是非常不同的,但因为它不是......我正在寻找有关如何解决这个问题的建议。

如果我能以某种方式使用接口并使用不同的实现(使用不同的数据库),那应该是可行的方法,但由于所有代码都已经依赖于类型化的(SqlConnection、Sql.Data.SqlClient.SqlCommand 等)参数,我没有办法避免这种情况..

其他选择是购买 Sql Standard,它比 Express Edition 贵得多。或尝试归档未积极使用的旧数据并将数据库大小保持在限制以下,或者可能创建多个“数据”数据库(应用程序工作的数据)并将其中一个用于应用程序数据(用户/角色/等)

这里只是一个想法,如果这个应用程序是用 python 编写的……改变这种类型会更容易吗?

【问题讨论】:

恐怕如果你的代码库深深依赖于那个命名空间,这将是一次重大的重新设计。您可能应该考虑首先切换到从具体数据库中更好地抽象的设计,然后在第二步中更改为 MySQL。 是的,如果必须继续进行重构,则必须构建抽象层以避免未来的痛苦。 ADO.NET 类实现接口abstract classes and class factories。从一个提供程序切换到另一个提供程序就像更改 app.config 中的设置一样简单,只要应用程序使用DbConnectionDbCommand 等。这在 Python 中没有什么不同。如果您使用特定于提供程序的类,您将无法迁移 顺便说一句,该代码很糟糕 - 看起来它试图通过使用单例连接而不是默认连接池来模拟类工厂而没有任何好处甚至损害性能。我敢打赌,为了防止这些全局连接和事务相互阻塞,会有很多麻烦。我会更关心 MySQL 将如何对此做出反应 鉴于代码状态不佳,我建议首先使用 SQL Server Express 2017 并选择压缩,按年份对数据进行分区并将旧数据移出。与尝试使用如此脆弱的代码迁移到另一个数据库相比,风险要小得多。这可能会完全缓解这个问题。在任何情况下,它都会为您赢得至少清理数据访问代码的时间,或者迁移到 ADO.NET 的类工厂模型,或者引入像 EF Core/NH 这样的真正 ORM 或像 Dapper 这样的 microORM。 GetOrmConnectionString() 非常可疑 - 有人尝试构建自定义 ORM 吗? 【参考方案1】:

前段时间我遇到过非常相似的情况,但在那种情况下,我不得不将 MySQL 代码迁移到 SQL Server 代码。

底线是您必须重构代码。不仅在 .NET 级别,您的存储过程也必须更新,而且 SQL Server 存储过程不是 100% 与 MySQL 存储过程兼容。存在语法差异。

好消息是,就 SQL Server 和 MySQL 而言,ADO.NET 代码非常相似。毕竟SqlConnection 和MySqlConnection 继承自同一个类DbConnection。同样,SqlDataAdapter 和 MySqlDataAdapter 继承自同一个类 DbDataAdapter。对于所有其他 ADO.NET 类都是如此。

您显然可以继续重构现有的 ADO.NET 和存储过程代码。但是,就我而言,我没有选择这种方法。相反,我更多地将其视为实现一个额外的数据提供者。这样,我现有的数据访问代码保持不变。这可能需要更多的工作,但它确保我可以在任何时候出于任何原因回到我之前的实现。

你有另一个选择,你应该考虑。使用基于云的数据库比如 Azure Sql 数据库怎么样?这样一来,您只需花费您选择的大小和性能层。

【讨论】:

ADO.NET 基于类工厂。如果代码需要可移植,它应该只使用抽象类并使用类工厂创建实例。可以在 app.config 或 web.config 中配置要使用的提供程序 是的,当涉及到重新设计和重构代码时,天空就是极限!问题是保持现有实现不变并构造一个新的实现是否是一个好主意,该接口将两个实现绑定到一个共同的合同。 给出已发布代码的状态?这看起来是 2005 年之前由试图构建他/她自己的 ORM 的人编写的 - 检查所有 GetConnectionGetCurrentConnectionGetNewSQLConnectionGetOrmConnectionString 方法。 SQL Server 和 MySQL 之间的并发模型差异可能会导致相当多的问题 或者显然是永恒的联系——一想到锁的积累和交易,我就不寒而栗 我不想评判代码的设计。是的,它看起来有点不合常规。我只是想确保我提供最好的建议来解决手头的问题。当然,如果他有时间和金钱重新设计代码,那么他可能会更好。

以上是关于有没有办法轻松地将大量依赖 SqlConnection 的代码切换到 MySqlConnection的主要内容,如果未能解决你的问题,请参考以下文章

基础概念——什么是POSIX

是否可以轻松地将所有提交从一个分支移动到另一个分支作为一个提交? [复制]

如何使用 AlmofireImage 最轻松地将 NSURLCache 的内存容量设置为零?

有没有办法用golang将PDF转换为jpeg?

有没有办法让 IFRAME 中的内容溢出到父框架上?

CentOS 6.5本地yum源配置(断网情况下轻松安装各种依赖包)