什么是为.NET产品支持多个数据库的最佳方法?

12

我们正在设计一款能够支持多个数据库的产品。目前,我们正在这样做,以便我们的代码支持 MS SQL 和 MySQL:

namespace Handlers
{
    public class BaseHandler
    {
        protected string connectionString;
        protected string providerName;

        protected BaseHandler()
        {
            connectionString = ApplicationConstants.DatabaseVariables.GetConnectionString();
            providerName = ApplicationConstants.DatabaseVariables.GetProviderName();
        }
    }
}

namespace Constants
{
    internal class ApplicationConstants
    {
        public class DatabaseVariables
        {
            public static readonly string SqlServerProvider = "System.Data.SqlClient";
            public static readonly string MySqlProvider = "MySql.Data.MySqlClient";

            public static string GetConnectionString()
            {
                return ConfigurationManager.ConnectionStrings["CONNECTION_STRING"].ConnectionString; 
            }

            public static string GetProviderName()
            {
                return ConfigurationManager.ConnectionStrings["CONNECTION_STRING"].ProviderName;
            }
        }
    }
}

namespace Handlers
{
    internal class InfoHandler : BaseHandler
    {
        public InfoHandler() : base()
        {
        }

        public void Insert(InfoModel infoModel)
        {
            CommonUtilities commonUtilities = new CommonUtilities();
            string cmdInsert = InfoQueryHelper.InsertQuery(providerName);
            DbCommand cmd = null;
            try
            {
                DbProviderFactory provider = DbProviderFactories.GetFactory(providerName);
                DbConnection con = LicDbConnectionScope.Current.GetOpenConnection(provider, connectionString);
                cmd = commonUtilities.GetCommand(provider, con, cmdInsert);
                commonUtilities.PrepareCommand(cmd, infoModel.AccessKey, "paramAccessKey", DbType.String, false, provider, providerName);
                commonUtilities.PrepareCommand(cmd, infoModel.AccessValue, "paramAccessValue", DbType.String, false, provider, providerName);
                cmd.ExecuteNonQuery();
            }
            catch (SqlException dbException)
            {
                //-2146232060 for MS SQL Server
                //-2147467259 for MY SQL Server
                /*Check if Sql server instance is running or not*/
                if (dbException.ErrorCode == -2146232060 || dbException.ErrorCode == -2147467259)
                {
                    throw new BusinessException("ER0008");
                }
                else
                {
                    throw new BusinessException("GENERIC_EXCEPTION_ERROR");
                }
            }
            catch (Exception generalException)
            {
                throw generalException;
            }
            finally
            {
                cmd.Dispose();
            }
        }
    }
}

namespace QueryHelpers
{
    internal class InfoQueryHelper
    {
        public static string InsertQuery(string providerName)
        {
            if (providerName == ApplicationConstants.DatabaseVariables.SqlServerProvider)
            {
                return @"INSERT INTO table1
           (ACCESS_KEY
           ,ACCESS_VALUE)
     VALUES
           (@paramAccessKey
           ,@paramAccessValue) ";
            }
            else if (providerName == ApplicationConstants.DatabaseVariables.MySqlProvider)
            {
                return @"INSERT INTO table1
           (ACCESS_KEY
           ,ACCESS_VALUE)
     VALUES
           (?paramAccessKey
           ,?paramAccessValue) ";
            }
            else
            {
                return string.Empty;
            }
        }
    }
}

你能否建议是否有更好的方法来完成这个任务?此外,这种方法的优缺点是什么?


2
我建议你将代码分成不同的<pre><code></code></pre>块,以便我们更容易阅读。现在的情况是,有很多代码溢出了右边界,只有一个水平滚动条远远地向下滚到了代码的末尾。 - Alfred Myers
10个回答

10

无论你做什么,不要编写自己的映射代码。这个已经完成了很多遍,而且可能比你手写的好上一百万倍。

毫无疑问,你应该使用NHibernate。它是一个对象关系映射器,可以使数据库访问透明:你定义一组表示数据库中每个表的 DAL 类,并使用 NHibernate 提供程序执行针对数据库的查询。NHibernate 将动态生成所需的 SQL 来查询数据库并填充你的 DAL 对象。

NHibernate 的好处在于它会基于你在配置文件中指定的内容生成 SQL。开箱即用,它支持 SQL Server、Oracle、MySQL、Firebird、PostGres 和其他一些数据库


由于怀疑 < 机器精度,因此不是。 - Juliet

5

3

针对您目前的需求,我同意使用NHibernate...

只是想指出您的类层次结构中的一些问题...

最好使用接口

例如(只需检查文档或互联网以获取确切的语法)

Interface IDBParser  
    Function1  
    Function2  

class MSSQLParser : IDBParser  
    Function1  
    Function2  

class MySQLParser : IDBParser  
    Function1  
    Function2 

然后在你的代码中,你可以使用这个接口

Main()  
    IDBParser dbParser;  
    if(...)  
       dbParser = new MSSQLParser();  
    else  
       dbParser = new MySQLParser();  

    SomeFunction( dbParser );  

// the parser can be sent by parameter, global setting, central module, ...  
    SomeFunction( IDBParser dbParser)  
      dbParser.Function1();  

这样做可以更容易地管理代码,避免重复的if/else条件语句。同时,添加其他数据库也会更加容易。另一个好处是通过发送模拟对象来帮助进行单元测试。


2
如果你必须自己编写代码而不使用提供统一访问的产品,请记住像SqlDataAdapter和OracleDataAdapter这样的对象继承自通用的DbDataAdapter(至少在运行时的较新版本中)。如果你向下转换到DbDataAdapter,你可以编写能够在需要同时处理两个数据库的地方工作的代码。你的一些代码将会像这样:
DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter;

一旦你进行了转换,无论是SqlDataAdapter还是OracleDataAdapter,调用方式都是相同的。

但是,请记住编写两个数据库的代码意味着使用仅存在于这两个数据库中的功能,并且必须解决两者的缺陷。这并不是一个好主意。


2
如果您需要将数据库条目映射到对象,我建议您使用其他人已经提出的解决方案:NHibernate。如果这对您的应用程序来说似乎过于复杂,并且您想采用Ado.net方法并且不需要O/RM解决方案,则应查看Spring.net团队所做的工作并了解Ado.Net Provider Abstraction。

1

有一些对象关系映射层可以支持多种数据库技术,比如Entity Spaces


1

在这种情况下,最好的方法是创建一个分层架构,将所有与数据库相关的内容仅放在数据访问层中。然后,您可以拥有DAO层的不同实现,例如Oracle、SQL Server等。

您应该使用接口将业务层与DAO层分离,以便您的业务层只使用它们来访问DAO层。因此,您可以完美地交换DAO层的底层实现,以在Oracle DB或任何您喜欢的系统上运行。

另一个好建议是查看像Scott已经建议的对象关系映射器。我会看一下NHibernate或Entity Framework。


1

许多人建议使用 O/R 映射框架,例如 NHibernate。这是一个相当合理的方法,除非出于某些原因您不想使用 O/R 映射器。像 NHibernate 这样的东西可能会让您完成 95% 以上的工作,但您可能需要编写一些自定义 SQL。如果是这种情况,请不要惊慌; 您仍然可以为其余部分制定临时解决方案。

在这种情况下,将需要自定义 SQL 的部分分离出来成为特定平台的插件模块。根据需要为要支持的各个数据库平台编写 Oracle、MySQL、SQL Server(等)插件。

ADO.Net 可以很容易地包装存储过程,因此您可能能够将平台相关层移动到一些存储过程中,向中间层呈现一个更或多或少一致的 API。仍然存在一些平台依赖项(例如 SQL Server 变量名称上的 '@' 前缀),因此您需要制定一个通用的存储过程包装机制(这并不难)。

幸运的是,在这种方式下需要拆分的特定操作数量应该相对较小,因此维护插件所需的工作量将受到限制。


0

解决这个问题的一种方法是设计应用程序完全使用断开连接的数据集,并编写一个数据访问组件,处理从不同数据库品牌中获取数据,以及将应用程序对数据集所做的更改持久化到原始数据库中。

优点:.Net中的数据集编写良好,易于使用和强大,并且提供了处理基于表格数据的方法和工具。

缺点:如果您的应用程序需要在客户端处理极大量的数据,则此方法可能会出现问题。


0

目前,微软的实体框架存在一些缺陷,其中一些可能会成为应用程序预期架构的瓶颈。

根据我所看到和了解的V2版本,它将随着.Net 4一起发布,我认为它肯定值得关注。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接