小菜上回梦到哪了?
上回说到,小菜手头上已经有了针对Sql数据库的设计,和一个针对Access数据库的设计.
那如何用好他们呢,来支持多数据库呢?
那在支持多数据库之前,小菜和大家一起来看下.Net Framework源码中System.Data中的代码组织.
.Net Framework的源代码,可以从 这里 进行下载(食草笨笨熊提供下载链接)http://www.cnblogs.com/ghost_boy
有很少的部份代码在其中没有比如:IDbConnecion.cs等.大家可以参看: 这里 Google的代码搜索功能不错
IDbCommand(接口),DbCommand(抽象类),SqlCommand(Sql具体实现),OleDbCommand(Access具体实现)
IDataReader(接口),DbDataReader(抽象类),SqlDataReader(Sql具体实现),OleDbDataReader(Access具体实现)
IDataParameter(接口),DbParameter(抽象类),SqlParameter(Sql具体实现),OleDbParameter(Access具体实现)
了解了这些之后,还是回到我们的目标吧,支持多数据库.
那还是用之前的第一个例子,遍历dnt_forums表,输出fid与name来说明吧.
1)Sql数据库返回的是SqlDataReader而Access数据库返回的是OleDbDataReader
而它们二者都是继承至DbDataReader
那么,我们只要提供一个公共的接口. DbDataReader GetForums().然后让两种数据库都实现之,
然后Access数据库就调用Access的实现,Sql数据库就调用Sql的实现.不就行喽.
这就叫做针对接口编程,而不是针对实现编程
那就试一试吧.
那接下来,让我们来调用它吧.
如果是Sql数据库的话,就使用new Discuz.Data.SqlServer.ForumManage();
如果是Access数据库的话.就使用new Discuz.Data.Access.ForumManage();
其它都无需修改,这就是针对接口编程的好处.
这时老大过来看小菜,看小菜这段时间是否有长进.
看了小菜的代码说到....小菜啊,我们看问题的时候,有时可以试着把问题放大,比如在很多地方都出现这样东西的话会出现什么情况.
小菜陷入了沉思,脑海中回旋着老大的话......
是啊,之前我们遇到的很多问题不都是这种情况.
上面的也属于这种情况,如果上面的代码在很多地方出现的话.
那么我们要从Sql数据库改为Access数据库的话,那不是要把代码中所有new Discuz.Data.SqlServer.ForumManage();
都改为new Discuz.Data.Access.ForumManage();
噢..天呐....
咦,,有了,我们新建一个类来管理它的创建.试试吧.
那我们之前的代码就从IForumManage forum = new Discuz.Data.SqlServer.ForumManage();
改成IForumManage forum = ForumFactory.CreateForumManage("SqlServer");
看起来不错,但这是无法逃过大家明亮的双眼...对这招不过是移花接木...
改数据库时我们同样要把所有的ForumFactory.CreateForumManage("SqlServer");
改为ForumFactory.CreateForumManage("Access");
还过好像改起来比较方便了,少写几个字母了....:)
小菜突然想起之前自己在做配置处理的时候,在DNT.config中有存放<DbType>SqlServer</DbType>
那么,小菜只要在ForumFactory.CreateForumManage中取出该项结点的值,并判断它的值不就可以了吗.
改变数据库,只要修改DNT.config中<DbType>Access</DbType>便可了.代码不用改动了.
好马上动手.
那小菜之前的调用也从IForumManage forum = ForumFactory.CreateForumManage("SqlServer");
正式改为IForumManage forum = ForumFactory.CreateForumManage();
小菜初步达到多数据库的要求了,革命尚未成功,战士还需努力.
下回见
上回说到,小菜手头上已经有了针对Sql数据库的设计,和一个针对Access数据库的设计.
那如何用好他们呢,来支持多数据库呢?
那在支持多数据库之前,小菜和大家一起来看下.Net Framework源码中System.Data中的代码组织.
.Net Framework的源代码,可以从 这里 进行下载(食草笨笨熊提供下载链接)http://www.cnblogs.com/ghost_boy
有很少的部份代码在其中没有比如:IDbConnecion.cs等.大家可以参看: 这里 Google的代码搜索功能不错
pubic interface IDisposable
{
void Dispose();
}
public interface IDbConnection : IDisposable
{
void Close();
IDbCommand CreateCommand();
void Open();
}
public abstract class DbConnection : IDbConnection
{
abstract public void Close();
public DbCommand CreateCommand()
{
return CreateDbCommand();
}
IDbCommand IDbConnection.CreateCommand()
{
return CreateDbCommand();
}
abstract public DbCommand CreateDbCommand();
abstract public void Open();
}
public sealed class SqlConnection : DbConnection
{
public SqlConnection() : this(String.Empty)
{}
public SqlConnection(string connectionString)
{
Init(connectionString);
}
private void Init(string connection)
{
ConnectionString = connectionString;
}
override public void Close()
{
具体实现Sql数据库关闭
}
new public SqlCommand CreateCommand()
{
SqlCommand command = new SqlCommand();
command.Connection = this;
return command;
}
override public void Open()
{
具体实现Sql数据库打开
}
}
public sealed class OleDbConnection : DbConnection
{
public OleDbConnection() : this(String.Empty)
{}
public OleDbConnection(string connectionString)
{
Init(connectionString);
}
private void Init(string connection)
{
ConnectionString = connectionString;
}
override public void Close()
{
具体实现Access数据库关闭
}
new public OleDbCommand CreateCommand()
{
OleDbCommand command = new OleDbCommand();
command.Connection = this;
return command;
}
override public void Open()
{
具体实现Access数据库打开
}
}
IDbConnection(接口),DbConnection(抽象类),SqlConnection(Sql具体实现),OleDbConnection(Access具体实现){
void Dispose();
}
public interface IDbConnection : IDisposable
{
void Close();
IDbCommand CreateCommand();
void Open();
}
public abstract class DbConnection : IDbConnection
{
abstract public void Close();
public DbCommand CreateCommand()
{
return CreateDbCommand();
}
IDbCommand IDbConnection.CreateCommand()
{
return CreateDbCommand();
}
abstract public DbCommand CreateDbCommand();
abstract public void Open();
}
public sealed class SqlConnection : DbConnection
{
public SqlConnection() : this(String.Empty)
{}
public SqlConnection(string connectionString)
{
Init(connectionString);
}
private void Init(string connection)
{
ConnectionString = connectionString;
}
override public void Close()
{
具体实现Sql数据库关闭
}
new public SqlCommand CreateCommand()
{
SqlCommand command = new SqlCommand();
command.Connection = this;
return command;
}
override public void Open()
{
具体实现Sql数据库打开
}
}
public sealed class OleDbConnection : DbConnection
{
public OleDbConnection() : this(String.Empty)
{}
public OleDbConnection(string connectionString)
{
Init(connectionString);
}
private void Init(string connection)
{
ConnectionString = connectionString;
}
override public void Close()
{
具体实现Access数据库关闭
}
new public OleDbCommand CreateCommand()
{
OleDbCommand command = new OleDbCommand();
command.Connection = this;
return command;
}
override public void Open()
{
具体实现Access数据库打开
}
}
IDbCommand(接口),DbCommand(抽象类),SqlCommand(Sql具体实现),OleDbCommand(Access具体实现)
IDataReader(接口),DbDataReader(抽象类),SqlDataReader(Sql具体实现),OleDbDataReader(Access具体实现)
IDataParameter(接口),DbParameter(抽象类),SqlParameter(Sql具体实现),OleDbParameter(Access具体实现)
了解了这些之后,还是回到我们的目标吧,支持多数据库.
那还是用之前的第一个例子,遍历dnt_forums表,输出fid与name来说明吧.
1)Sql数据库返回的是SqlDataReader而Access数据库返回的是OleDbDataReader
而它们二者都是继承至DbDataReader
那么,我们只要提供一个公共的接口. DbDataReader GetForums().然后让两种数据库都实现之,
然后Access数据库就调用Access的实现,Sql数据库就调用Sql的实现.不就行喽.
这就叫做针对接口编程,而不是针对实现编程
那就试一试吧.
using System;
using System.Data;
namespace Discuz.Data
{
public interface IForumManage
{
IDataReader GetForums();
}
}
Sql数据库实现using System.Data;
namespace Discuz.Data
{
public interface IForumManage
{
IDataReader GetForums();
}
}
using System;
using System.Data;
using System.Data.Common;
namespace Discuz.Data.SqlServer
{
public class ForumManage : IForumManage
{
public IDataReader GetForums()
{
string cmdText = "select fid,name from dnt_forums";
return SqlHelper.ExecuteReader(CommandType.Text, cmdText, null);
}
}
}
Access数据库的实现using System.Data;
using System.Data.Common;
namespace Discuz.Data.SqlServer
{
public class ForumManage : IForumManage
{
public IDataReader GetForums()
{
string cmdText = "select fid,name from dnt_forums";
return SqlHelper.ExecuteReader(CommandType.Text, cmdText, null);
}
}
}
using System;
using System.Data;
using System.Data.Common;
namespace Discuz.Data.Access
{
public class ForumManage : IForumManage
{
public IDataReader GetForums()
{
string cmdText = "select fid,name from dnt_forums";
return AccessHelper.ExecuteReader(CommandType.Text, cmdText, null);
}
}
}
using System.Data;
using System.Data.Common;
namespace Discuz.Data.Access
{
public class ForumManage : IForumManage
{
public IDataReader GetForums()
{
string cmdText = "select fid,name from dnt_forums";
return AccessHelper.ExecuteReader(CommandType.Text, cmdText, null);
}
}
}
那接下来,让我们来调用它吧.
using System;
using System.Data;
using Discuz.Data;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
IForumManage forum = new Discuz.Data.SqlServer.ForumManage(); //Sql数据库
//IForumManage forum = new Discuz.Data.Access.ForumManage(); //Access数据库
IDataReader reader = forum.GetForums();
while (reader.Read())
{
Response.Write(reader["fid"]);
Response.Write(reader["name"]);
}
}
}
现在看起来终于像个支持多数据库的样子了.using System.Data;
using Discuz.Data;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
IForumManage forum = new Discuz.Data.SqlServer.ForumManage(); //Sql数据库
//IForumManage forum = new Discuz.Data.Access.ForumManage(); //Access数据库
IDataReader reader = forum.GetForums();
while (reader.Read())
{
Response.Write(reader["fid"]);
Response.Write(reader["name"]);
}
}
}
如果是Sql数据库的话,就使用new Discuz.Data.SqlServer.ForumManage();
如果是Access数据库的话.就使用new Discuz.Data.Access.ForumManage();
其它都无需修改,这就是针对接口编程的好处.
这时老大过来看小菜,看小菜这段时间是否有长进.
看了小菜的代码说到....小菜啊,我们看问题的时候,有时可以试着把问题放大,比如在很多地方都出现这样东西的话会出现什么情况.
小菜陷入了沉思,脑海中回旋着老大的话......
是啊,之前我们遇到的很多问题不都是这种情况.
上面的也属于这种情况,如果上面的代码在很多地方出现的话.
那么我们要从Sql数据库改为Access数据库的话,那不是要把代码中所有new Discuz.Data.SqlServer.ForumManage();
都改为new Discuz.Data.Access.ForumManage();
噢..天呐....
咦,,有了,我们新建一个类来管理它的创建.试试吧.
using System;
using System.Reflection;
namespace Discuz.Data
{
public class ForumFactory
{
public static IForumManage CreateForumManage(string dbType)
{
IForumManage forumManage = null;
switch (dbType)
{
case "Access" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.Access").CreateInstance("Discuz.Data.Access.ForumManage");
break;
case "SqlServer" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.SqlServer").CreateInstance("Discuz.Data.SqlServer.ForumManage");
break;
default :
throw new Exception("暂不支持其它数据库类型");
}
return forumManage;
}
}
}
using System.Reflection;
namespace Discuz.Data
{
public class ForumFactory
{
public static IForumManage CreateForumManage(string dbType)
{
IForumManage forumManage = null;
switch (dbType)
{
case "Access" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.Access").CreateInstance("Discuz.Data.Access.ForumManage");
break;
case "SqlServer" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.SqlServer").CreateInstance("Discuz.Data.SqlServer.ForumManage");
break;
default :
throw new Exception("暂不支持其它数据库类型");
}
return forumManage;
}
}
}
那我们之前的代码就从IForumManage forum = new Discuz.Data.SqlServer.ForumManage();
改成IForumManage forum = ForumFactory.CreateForumManage("SqlServer");
看起来不错,但这是无法逃过大家明亮的双眼...对这招不过是移花接木...
改数据库时我们同样要把所有的ForumFactory.CreateForumManage("SqlServer");
改为ForumFactory.CreateForumManage("Access");
还过好像改起来比较方便了,少写几个字母了....:)
小菜突然想起之前自己在做配置处理的时候,在DNT.config中有存放<DbType>SqlServer</DbType>
那么,小菜只要在ForumFactory.CreateForumManage中取出该项结点的值,并判断它的值不就可以了吗.
改变数据库,只要修改DNT.config中<DbType>Access</DbType>便可了.代码不用改动了.
好马上动手.
using System;
using System.Reflection;
using Discuz.Config;
namespace Discuz.Data
{
public class ForumFactory
{
public static IForumManage CreateForumManage()
{
IForumManage forumManage = null;
switch (BaseConfigFileManager.GetDbType)
{
case "Access" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.Access").CreateInstance("Discuz.Data.Access.ForumManage");
break;
case "SqlServer" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.SqlServer").CreateInstance("Discuz.Data.SqlServer.ForumManage");
break;
default :
throw new Exception("暂不支持其它数据库类型");
}
return forumManage;
}
}
}
这种做法其实叫依赖注入它和工厂模式会配合的很好.using System.Reflection;
using Discuz.Config;
namespace Discuz.Data
{
public class ForumFactory
{
public static IForumManage CreateForumManage()
{
IForumManage forumManage = null;
switch (BaseConfigFileManager.GetDbType)
{
case "Access" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.Access").CreateInstance("Discuz.Data.Access.ForumManage");
break;
case "SqlServer" :
forumManage = (IForumManage)Assembly.Load("Discuz.Data.SqlServer").CreateInstance("Discuz.Data.SqlServer.ForumManage");
break;
default :
throw new Exception("暂不支持其它数据库类型");
}
return forumManage;
}
}
}
那小菜之前的调用也从IForumManage forum = ForumFactory.CreateForumManage("SqlServer");
正式改为IForumManage forum = ForumFactory.CreateForumManage();
小菜初步达到多数据库的要求了,革命尚未成功,战士还需努力.
下回见