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;
            }
        }
    }
}

您能否建议是否有更好的方法?还有这种方法的优缺点是什么?

4

10 回答 10

10

无论您做什么,都不要编写自己的映射代码。它以前已经做过了,而且它可能比你手写的任何东西都要好一百万倍。

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

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

于 2009-08-21T12:19:54.767 回答
5

我会使用NHibernate

这是很好的初学者教程

于 2009-08-21T12:19:25.313 回答
3

对于您当前的需要,我同意 NHibernate ......

只是想指出你的类层次结构......

你会更好地使用接口

喜欢(只需检查文档或 Internet 以了解确切的语法)

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 条件。添加其他数据库也会容易得多。另一个优点是它可以通过发送模拟对象来帮助您进行单元测试。

于 2009-08-22T15:42:22.540 回答
2

如果您必须自己编写代码而不使用提供统一访问的产品,请记住 SqlDataAdapter 和 OracleDataAdapter 等对象继承自通用 DbDataAdapter(至少在运行时的更高版本中)。如果向下转换为 DbDataAdapter,则可以在对两个数据库执行相同操作的地方编写适用于两个数据库的代码。你的一些代码看起来有点像这样:

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter;

一旦你放弃了,它是 SqlDataAdapter 还是 OracleDataAdapter 都没有关系。你可以用同样的方式来称呼它。

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

于 2009-08-21T13:14:29.963 回答
2

如果您需要从数据库条目到对象的映射,我建议您使用其他已经建议的解决方案:NHibernate。如果这对您的应用程序来说似乎是多余的,并且您想使用 Ado.net 方法并且不需要 O/RM-soultion,那么您应该看看 Spring.net 的人做了什么并了解Ado.Net提供者抽象。

于 2009-08-21T13:25:00.840 回答
1

那里有支持多种数据库技术的对象关系映射层,例如实体空间

于 2009-08-21T12:16:32.830 回答
1

在这种情况下总是好的是创建一个分层架构,其中所有与数据库相关的东西都只是在数据访问层中。然后你可以有你的 DAO 层的不同实现,一个用于 Oracle、SQL Server 等......

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

另一个好建议是看看像 Scott 已经建议的对象关系映射器。我会看看 NHibernate 或实体框架。

于 2009-08-21T12:21:10.400 回答
1

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

在这种情况下,取出确实需要自定义 SQL 的部分并将它们分离到特定于平台的插件模块中。根据需要为您要支持的各个数据库平台编写 Oracle、MySQL、SQL Server(等)插件。

ADO.Net 使包装存储过程变得相当容易,因此您可以将平台相关层向下移动到一些存储过程中,从而为中间层提供或多或少的一致性 API。仍然存在一些平台依赖性(例如 SQL Server 变量名称上的“@”前缀),因此您需要创建一个通用的 sproc 包装器机制(这并不难)。

运气好的话,您需要以这种方式进行的特定操作数量将相当少,因此维护插件的工作量将受到限制。

于 2009-08-21T13:07:27.687 回答
0

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

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

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

于 2009-08-21T12:20:10.027 回答
0

目前,微软的实体框架有一些缺点,其中一些可能会破坏交易,具体取决于应用程序的预期架构。

从我所看到和读到的关于将随 .Net 4 一起提供的 V2,我认为它当然值得一看。

于 2009-08-21T12:23:59.543 回答