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

时间:2009-08-21 12:10:13

标签: c# design-patterns multiple-databases architecture

我们正在设计一种可以支持多个数据库的产品。我们目前正在做这样的事情,以便我们的代码支持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;
            }
        }
    }
}

您能否建议是否有更好的方法?该方法的优点和缺点是什么?

10 个答案:

答案 0 :(得分:10)

无论你做什么,不要编写自己的映射代码。它之前已经完成了,它可能比你手写的任何东西都要好上百万倍。

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

关于NHibernate的好处是它根据你在配置文件中指定的内容生成SQL。开箱即用,它支持SQL Server,Oracle,MySQL,Firebird,PostGres和a few other databases

答案 1 :(得分:5)

我会使用NHibernate

这里很好beginner tutorial

答案 2 :(得分:2)

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

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter;

一旦你下来了,无论是SqlDataAdapter还是OracleDataAdapter都没关系。你可以用同样的方式调用它。

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

答案 3 :(得分:2)

如果您需要从数据库条目到对象的映射,我建议您使用其他已经建议的解决方案:NHibernate。 如果这似乎对您的应用程序来说太过分了,并且您希望采用Ado.net方法并且不需要O / RM-soultion,那么您应该看一下Spring.net的人做了什么并了解{{3 }}

答案 4 :(得分:2)

根据您目前的需要,我同意NHibernate ......

只想指出你的班级层次结构......

您最好使用界面

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

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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

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

另一个好建议是看看斯科特已经建议的对象关系映射器。我将看一下NHibernate或Entity框架。

答案 7 :(得分:0)

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

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

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

答案 8 :(得分:0)

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

从我所看到和读到的关于V2的内容,它将与.Net 4一起发布,我认为它当然值得一看。

答案 9 :(得分:0)

很多人都提出了一个O / R映射框架,比如NHibernate。这是一种非常合理的方法,除非您出于某种原因不想使用O / R映射器。像NHibernate这样的东西可能会让你获得95%+,但你可能需要编写一些自定义SQL。如果是这样的话,不要惊慌失措;你仍然可以为其他人做一个特别的解决方案。

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

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

运气好的话,您需要以这种方式突破的具体操作数量相当少,因此维护插件的工作量将会受到限制。

相关问题