I have this problem:
In C# I'm making a program that should connect to various databases (SQLite, SQL Server Compact, MS Access, etc). I set in app.config a parameter called "dbType" (it could be 1 for SQLlite, 2 for SQL Server Compact, 3 for MS Access, etc.). This parameter should be changed by the user while the program is running, with a dropdown menu or something like this.
Then the program reads this parameter and creates an instance of an implementation of the database interface (IDatabase) that corresponds to the chosen database.
The code is:
class ObjectDatabaseCreator
{
protected ObjectDatabase objectDb;
protected Object objectDAO;
protected int dbType;
protected String dbName;
public ObjectDatabaseCreator()
{
}
public ObjectDatabaseCreator(String dbName)
{
this.dbType = ObjectConfiguration.getDbType();
this.dbName = dbName;
}
public ObjectDatabase getObjectDatabase()
{
//1 - SQLite; 2-SQLServer Compact; 3-SQLServer Express; 4-MS Access
switch (dbType)
{
case 1:
objectDb = new ObjectDatabase(new Database_Impl_1(dbName));
break;
case 2:
objectDb = new ObjectDatabase(new Database_Impl_2(dbName));
break;
case 3:
objectDb = new ObjectDatabase(new Database_Impl_3(dbName));
break;
case 4:
开发者_开发问答 objectDb = new ObjectDatabase(new Database_Impl_4(dbName));
break;
}
return objectDb;
}
}
Well, it seems that works but I would like to know if there is a possibility to make it easier to add another databases, I mean, if there will be another db I should modify this class, recompile, etc.
And how could I instantiate also the other implementation for BLL classes, let's say Person, Customer, etc ? These also changes and I should add more classes.
Thanks, Trav
take a look at MEF... it can be useful because it add the notion of catalog. Defines as many IDataBaseImplemention class as you want in assemblies located in a folder, and MEF will allow you to "import" all found classes.
MEF is included in the .Net framework (from the V4), but there are many other framework that can do the job.
I think there is something wrong with you design if business classes change based on the database engine being used. So I suggest normalizing your business classes.
As regards the database connections, You should be using the DbProviderFactories, DbProviderFactory, DbConnection etc. from the System.Data.Common assembly/namespace http://msdn.microsoft.com/en-us/library/9tahwysy.aspx
along with the connectionString section of the config file if you want to do this correctly. http://msdn.microsoft.com/en-us/library/ms178411(v=VS.85).aspx
If you want to just improve your current implementation, then use Factories for your databaseobject as well as business objects. But really, this will just become more of a problem with time.
You can add a map from the integer value to a class type. Something like this (untested):
// initialization somewhere:
Dictionary<int,Type> databases = new Dictionary<int,Type>();
databases.Add(1, Database_Impl_1);
databases.Add(2, Database_Impl_2);
// ...
// then later, in getObjectDatabase()
objectDb = new ObjectDatabase(databases[settingValue]);
Google inversion of control - there are frameworks for this.
The most generic way to do with would be to get the user to specify the assembly qualified name of the type that should be loaded. You can create an instance of an object given its type name using something like this:
IDatabase GetDatabase(string typeName)
{
var databaseType = Type.GetType(typeName);
if (databaseType == null)
{
return null;
}
return (IDatabase)Activator.CreateInstance(databaseType);
}
This then lets your users specify pretty much any implementation of IDatabase
- including ones contained in user provided assemblies:
IDatabase db = GetDatabase("EnterpriseLib.XmlDatabase, EnterpriseLib.XmlDatabase, Version=1.42.0.0, Culture=neutral, PublicKeyToken=AAAAAAAAAAAAAAAA"");
This should work as long as the assembly is contained in one of the folders in the assembly search path.
精彩评论