我目前正在创建一个支持MySQL和MSSQL数据库的C#应用程序。我遇到的问题是我的包装器。我的代码适用于MySQL,但我在修改它以支持多个数据库时遇到问题。
如果你看一下我的代码的精简版本,你会看到我有一个DBMySQL类型的dbConn对象,如果我只想要MySQL支持,这很好。我需要修改DBMySQL是通用的,这样我就可以运行dbConn = new DBMySQL(...)和dbConn = DBMSSQL(...)然后我可以简单地调用dbConn.SomeMethod()并让它在相应的数据库上运行。我希望尽可能保持相同的设置,因为我在DBMySQL和DBMSSQL类中有其他东西用于批量插入数据库和特定的错误检查。
我正在考虑/尝试声明像对象dbConn之类的东西,然后操纵它,但这并没有那么顺利。然后我尝试使用enum类的对象类型,但我也遇到了问题。我知道有很多第三方库可以完成所有这些,但我更愿意使用我自己的代码。
有没有人有任何建议我如何修改我的DBWrapper来解决这个问题?
//WRAPPER CLASS THAT CALLS DBMySQL, ISSUE IS I NOW NEED TO SUPPORT
//DBMSSQL as well, not just DBMySQL
class DBWrapper
{
DBMySQL dbConn;
public DBWrapper(...,string type)
{
if(type.Equals("MySQL")
{
dbConn = new DBMySQL(...);
}
//NEED TO REWORK TO SUPPORT THIS BELOW!!
else if(type.Equals("MSSQL")
{
//NEED TO MODIFY TO SUPPORT MSSQL
//ISSUE IS DbConn is of type DBMySQL
//SO I CANNOT GO
// DbConn = new DBMSSQL(...);
// any ideas?
}
}
public void setQuery(string myquery)
{
dbConn.setQuery(myquery);
}
}
class DBMySQL
{
public string dbinfo;
string query;
public DBMySQL(...)
{
dbinfo = ...;
}
public void setQuery(...)
{
query = myquery;
}
}
//NEED TO RE-WORK WRAPPER TO SUPPORT THIS
class DBMSSQL
{
public string dbinfo;
string query;
public DBMSSQL(...)
{
dbinfo = ...;
}
public void setQuery(...)
{
query = myquery;
}
}
此时我会感激任何帮助,所以如果你正在查看这篇文章并有想法,请告诉我,因为我已经花了一整天时间。
答案 0 :(得分:6)
您需要创建的界面将描述您希望数据访问类执行的操作。
E.g。来自您的样本
public interface IDBAccess
{
void setQuery(...);
}
public class DBMySQL : IDBAccess
{
public string dbinfo;
string query;
public DBMySQL(...)
{
dbinfo = ...;
}
public void setQuery(...)
{
query = myquery;
}
}
public class DBMSSQL : IDBAccess
{
public string dbinfo;
string query;
public DBMSSQL(...)
{
dbinfo = ...;
}
public void setQuery(...)
{
query = myquery;
}
}
此时你可以这样做:
IDBAccess dbConn;
dbConn = new DBMySQL();
dbConn = new DBMSSQL();
请注意,您不熟悉这一点,建议您查看NHibernate或Castle ActiveRecord和Castle Windsor可能没有用。但是将它们铭记在未来。
答案 1 :(得分:2)
你不应该创建一个处理这两个数据库的大类。您应该为包装器IDBWrapper
创建一个公共接口,然后为每个数据库单独实现。
在此之后,您可以创建一些逻辑,为您选择正确的实现。每次需要包装器时,你都不想写这样的东西:
IDBWrapper db = (useMySQL ? new MySqlDBWrapper(...) : new MsSqlDBWrapper(...));
有几种选择。您可以使用抽象工厂,但实际上任何抽象数据库包装器创建的东西都可以工作。
答案 2 :(得分:2)
您是否有特定原因想要在C#中重新实现数据库层?你有没有考虑过使用说; Entity Framework,NHibernate或任何其他.NET ORM?这将很好地包装所有数据访问,而不必过多担心实现细节。此外,它们还提供其他优势,例如将表映射到类,(即根据表中的内容和其他方式填充类),缓存和各种其他功能。
或者,如果您确实想创建自己的,那么您需要做的是声明一个接口,让所有数据库连接从该接口继承并将连接实例存储在接口类型的属性中。即:
public interface IDatabaseConnection
{
void setQuery(string myQuery);
}
public class DBWrapper
{
private IDatabaseConnection Connection { get; set; }
public DBWrapper(string type)
{
if(type == "MySql")
Connection = new DBMySQL();
else if(type == "MsSql")
Connection = new DBMSSQL();
}
}
public class DBMySQL : IDatabaseConnection
{
...
}
public class DBMSSQL : IDatabaseConnection
{
...
}
答案 3 :(得分:1)
您还可以查看这些DB上的Generic Repository模式和ORM。
答案 4 :(得分:1)
在ADO.NET中,所有连接类都继承自System.Data.Common.DbConnection,所以你想要的实际内置于.NET中 - 你所要做的就是将连接存储在DbConnection
而不是SqlConnection
/ MySqlConnection
,并使用System.Data.Common中的类,而不是System.Data.Sql/MySql/
中的类。
在我看来,你的主要问题是没有真正的SQL标准 - 除了简单的选择和插入之外,你需要不同的语法来进行SqlServer和MySql查询。要解决这个问题,您需要使用Linq to SQL - 如果您不想依赖库,这是很多工作 - 或者,如果您只希望您的包装器执行 特定的< / em> 操作 - 您可以为每个数据库创建一个字典,用于存储这些操作的ready-for-String.Format
查询模板,并在运行时应用于执行这些操作的包装器方法。
答案 5 :(得分:0)
我能想到的一个快速入侵,就是创建一个具有必要支持的大型类,并根据用户选择的内容,使用相应的对象和类。此外,您可以为每个数据源创建一个类,然后创建一个登陆类,该类将根据用户选择的内容重新路由到正确的数据源提供程序类。不是很漂亮,但可能有用......