C# - 使项目 MySQL 和 SQL Server 兼容

Posted

技术标签:

【中文标题】C# - 使项目 MySQL 和 SQL Server 兼容【英文标题】:C# - Make a project MySQL and SQL Server compatible 【发布时间】:2018-12-13 10:46:49 【问题描述】:

我正在开发一个希望 MySQLMSQL 兼容的项目。 一切正常,但我有一个关于代码重复的小问题:

我对所有数据库查询都有一个单独的类,对于选择,我执行以下操作(例如对象“Profil”):

我有一个参数“ismysql”,如果我想使用 MySQL,我将其设置为 true,如果我想使用 Microsoft SQL Server,我将其设置为 false。

public Profil Select_profil(string query)
        
            Profil profil = new Profil();
            if (this.OpenConnection() == true)
            
                if (this.isMySQL)
                
                    MySqlCommand cmd = new MySqlCommand(query.Replace("[myDataBase].", ""), connection);
                    using (MySqlDataReader dataReader = cmd.ExecuteReader())
                    
                        while (dataReader.Read())
                        
                            profil.ID = Int32.Parse(dataReader["ID"].ToString().Trim());
                            profil.Nom = dataReader["PROFIL"].ToString().Trim();
                            profil.Famille = dataReader["FAMILLE"].ToString().Trim();
                            profil.Largeur = double.Parse(dataReader["LARGEUR"].ToString().Trim());
                            profil.Hauteur = double.Parse(dataReader["LARGEUR_AILE"].ToString().Trim());
                            profil.EpAile = double.Parse(dataReader["EP_AILE"].ToString().Trim());
                            profil.EpAme = double.Parse(dataReader["EP_AME"].ToString().Trim());
                            profil.Radius1 = double.Parse(dataReader["R"].ToString().Trim());
                            profil.Radius2 = double.Parse(dataReader["R2"].ToString().Trim());
                            profil.PdsLin = double.Parse(dataReader["PDS_LINEAIRE"].ToString().Trim());
                            profil.PaintSurf = double.Parse(dataReader["PAINT_SURF"].ToString().Trim());
                            profil.P08 = double.Parse(dataReader["P08"].ToString().Trim());
                            profil.P09 = double.Parse(dataReader["P09"].ToString().Trim());
                            profil.P10 = double.Parse(dataReader["P10"].ToString().Trim());
                            profil.P11 = double.Parse(dataReader["P11"].ToString().Trim());
                        
                    
                
                else
                
                    SqlCommand cmd = new SqlCommand(query, MSconnection);
                    using (SqlDataReader dataReader = cmd.ExecuteReader())
                    
                        while (dataReader.Read())
                        
                            profil.ID = Int32.Parse(dataReader["ID"].ToString().Trim());
                            profil.Nom = dataReader["PROFIL"].ToString().Trim();
                            profil.Famille = dataReader["FAMILLE"].ToString().Trim();
                            profil.Largeur = double.Parse(dataReader["LARGEUR"].ToString().Trim());
                            profil.Hauteur = double.Parse(dataReader["LARGEUR_AILE"].ToString().Trim());
                            profil.EpAile = double.Parse(dataReader["EP_AILE"].ToString().Trim());
                            profil.EpAme = double.Parse(dataReader["EP_AME"].ToString().Trim());
                            profil.Radius1 = double.Parse(dataReader["R"].ToString().Trim());
                            profil.Radius2 = double.Parse(dataReader["R2"].ToString().Trim());
                            profil.PdsLin = double.Parse(dataReader["PDS_LINEAIRE"].ToString().Trim());
                            profil.PaintSurf = double.Parse(dataReader["PAINT_SURF"].ToString().Trim());
                            profil.P08 = double.Parse(dataReader["P08"].ToString().Trim());
                            profil.P09 = double.Parse(dataReader["P09"].ToString().Trim());
                            profil.P10 = double.Parse(dataReader["P10"].ToString().Trim());
                            profil.P11 = double.Parse(dataReader["P11"].ToString().Trim());
                        
                    
                
                this.CloseConnection();
            
            return profil;
        

对于 MySQL 和 SQL Server,代码是相同的(除了 [MyDatabase].,我在 MySQL 的情况下替换),但我需要重复两次,因为在一种情况下我使用对象 MySqlCommand 和 MySqlDataReader,在第二种情况下我需要使用 SqlCommand 和 SqlDataReader。 不方便的是,当我在数据库中进行一些修改时,我需要全部更改两次(错误来源)。 有没有办法将代码分组并放置一次,而不使用函数?

【问题讨论】:

我已经使用 System.Data.Common.DbCommand(不是 SqlCommand,不是 mysqlCommand)完成了这项工作——我唯一改变的是连接字符串和创建我的连接对象的核心工厂 x.OpenConnection( )。我在存储过程背后隐藏了许多其他问题,并在极少数情况下动态更改原始 sql 语法。 MySql 和 SqlServer 库甚至没有在主数据层中引用。 DbCommand 抽象接口摆脱了您看到的 IF ELSE 问题, 感谢您的建议,我想我将从 System.Data.Common.DbCommand 开始,这似乎是我的起点。您能否提供一些有关如何使用它的示例的链接,因为目前找不到太多关于它的信息。 @Siegfried.V 而不是编辑您的问题以包含答案,您应该添加自己的答案,您可以接受。 @Richardissimo,好的,我会这样做,我只是相信我可以接受 zac 的回答,因为他给了我解决方案。 @Richardissimo 我明白了。事实上,我犹豫是否将 zac 答案标记为好答案,但正如您也评论的那样,它不像 cmets 那样清楚。所以我会等待他编辑他的答案以将其标记为解决方案,然后删除我的。对他更公平,因为他是给我解决方案的人。感谢您的评论。 【参考方案1】:

这里不要在 if..else.. 语句中应用切换逻辑,而应该按照之前的 cmets 中的建议编写一个单独的层用于数据访问。 该层将处理数据库选择和其他操作。

例如, 添加一个合同,比如 ICommand——这将在您当前的代码中用于代替 MySQLCommand 或 SQLCommand。 数据访问层将有一个工厂/类和函数,可以根据参数返回适当的命令。

同样,您可能在代码中的业务层执行的所有其他与数据库相关的操作都将移至您将创建的新层 DataAccessLayer。

已编辑: 感谢@Richardissimo 和@Siegfried.V 接受它作为答案。按照建议,我将代码放在这里,以便您可以接受它作为答案。

public IDataReader ExecuteReader(string query) 
    
         IDataReader dataReader = null; 
       if (this.isMySQL) 
      
         MySqlCommand cmd = new MySqlCommand(query.Replace("[myDataBase].", ""), 
         connection); 
         dataReader = cmd.ExecuteReader(); 
       
      else 
       
        SqlCommand cmd = new SqlCommand(query, connection); 
        dataReader = cmd.ExecuteReader(); 
      
        return dataReader; 
  

【讨论】:

谢谢,但现在我对上次的帖子不太了解,我不知道什么是写单独的层,不知道什么是合同或ICommand ...现在我正在搜索信息关于 SQL Surfer 建议的 System.Data.Common.DbCommand ,这似乎是一个好的开始,但很难找到有关如何使用它的一些信息 您应该了解分层架构,以使应用程序更加可重用和易于维护。从谷歌搜索开始。目前,一个简单的方法是创建一个辅助类和一个方法来执行决策部分和查询执行部分并返回数据结果。 请参考下面的示例代码以供参考...public IDataReader ExecuteReader(string query, string connection) IDataReader dataReader = null; if (this.isMySQL) MySqlCommand cmd = new MySqlCommand(query.Replace("[myDataBase].", ""), connection); dataReader = cmd.ExecuteReader(); else SqlCommand cmd = new SqlCommand(query, connection); dataReader = cmd.ExecuteReader(); return dataReader; 现在,从您的代码中调用此函数,例如...IDataReader reader = ExecuteReader(query, connection);,然后使用此阅读器获取值 感谢您的功能,它工作得很好,除了“连接”,它不是字符串而是对象。我将编辑我的问题,包括您的解决方案。关于分层架构,在谷歌搜索之后,我认为这就是我所做的。事实上,链接到数据库的函数都在一个单独的 .dll 文件中。但直到现在我只有 MySQL,然后决定实施 SQL 服务器(成本问题)。我缺少的是“IDataReader”,它解决了所有问题。【参考方案2】:

感谢 zac 的解决方案,我把代码放在这里:

public List<Profil> Select_profil(string query)
        
            List<Profil> list = new List<Profil>();
            if (this.OpenConnection() == true)
            
                IDataReader dataReader = ExecuteReader(query);
                while (dataReader.Read())
                
                    ...
                    ...
                
                this.CloseConnection();
            
            return list;
        

然后是ExecuteReader函数:

public IDataReader ExecuteReader(string query)
        
            IDataReader dataReader = null;
            if (this.isMySQL)
            
                MySqlCommand cmd = new MySqlCommand(query.Replace("[v-steel].", ""), connection);
                dataReader = cmd.ExecuteReader();
            
            else
            
                SqlCommand cmd = new SqlCommand(query, MSconnection); 
                dataReader = cmd.ExecuteReader();
            
            return dataReader;
        

关于连接蚂蚁MSconnection,这是两个私有对象:

private MySqlConnection connection;
private SqlConnection MSconnection;

【讨论】:

【参考方案3】:

如果您希望使用不同的数据库引擎并从设置中选择特定安装中的任何一个,您应该有一个数据访问层来实现可选数据库引擎的接口。为此,一种选择是拥有一个抽象类并从它继承以实现每个数据库引擎的特性。拥有一个实例化所需实现并使用它的工厂。

【讨论】:

以上是关于C# - 使项目 MySQL 和 SQL Server 兼容的主要内容,如果未能解决你的问题,请参考以下文章

SQL语句报错:You have an error in your SQL syntax; check the manual that corresponds to your MariaDB serv

mysql命令行导入sql脚本中文变问号问题

C# 中的简单 SQL 选择?

C#中简单操作Mysql数据库

C# 和 MySQL .NET 连接器 - 有啥方法可以防止泛型类中的 SQL 注入攻击?

C# - MySQL 与 Microsoft SQL Server [关闭]