Kal*_*pak 11 c# architecture design-patterns multiple-databases
我们正在设计一种可以支持多个数据库的产品.我们目前正在做这样的事情,以便我们的代码支持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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你能否建议是否有更好的方法吗?这种方法的优点和缺点是什么?
Jul*_*iet 10
无论你做什么,都不要编写自己的映射代码.它之前已经完成了,它可能比你用手写的任何东西都要好一百万倍.
毫无疑问,你应该使用NHibernate.它是一个对象关系映射器,它使数据库访问透明:您定义了一组代表数据库中每个表的DAL类,并使用NHibernate提供程序对您的数据库执行查询.NHibernate将动态生成查询数据库和填充DAL对象所需的SQL.
NHibernate的优点在于它根据您在配置文件中指定的内容生成SQL.开箱即用,它支持SQL Server,Oracle,MySQL,Firebird,PostGres和其他一些数据库.
对于您当前的需求,我同意 NHibernate...
只是想指出您的类层次结构中的一些内容......
你会更好地使用接口
就像(只需检查文档或互联网以获取确切的语法)
Interface IDBParser
Function1
Function2
class MSSQLParser : IDBParser
Function1
Function2
class MySQLParser : IDBParser
Function1
Function2
Run Code Online (Sandbox Code Playgroud)
然后在您的代码中您可以使用该接口
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();
Run Code Online (Sandbox Code Playgroud)
这样,管理起来会更容易,并且您的代码不会充满相同的 if/else 条件。添加其他数据库也会容易得多。另一个优点是它可以通过发送模拟对象来帮助您进行单元测试。