需求:在程序代码不做任何改动的情况,只要配置不同的数据库如:ACCESS,MS SQL,ORACLE等,则程序一样能执行。
整个解决方法最终的项目结构图:
1、建立IDAL类库项目,抽象数据访问接口。为每个表建立接口,规定各种操作(如增,删,改,查)
例如:数据库中有两个表,一个是用户表UserInfo,一个是帖子表Thread,则建立接口IUserInfoDAL,IThreadDAL
IUserInfoDAL代码如下:
IThreadDAL代码如下:
2、建立针对不同数据库的访问的DAL,引用IDAL项目,针对Access数据库建立OleDbDAL项目,针对Ms SQL数据库建立SQLServerDAL项目,针对Oracel数据库建立SQLServerDAL项目。在项目里实现IDAL接口中对表的各种操作定义。
(1)、OleDbDAL项目里对这两表操作代码如下:
UserInfoDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.OleDb;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.OleDbDAL
{
/// <summary>
/// 数据访问类UserInfoDAL。
/// </summary>
public class UserInfoDAL : IUserInfoDAL
{
public UserInfoDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int UID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int UID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.UserInfo GetModel(int UID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
ThreadDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.OleDb;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.OleDbDAL
{
/// <summary>
/// 数据访问类ThreadDAL。
/// </summary>
public class ThreadDAL : IThreadDAL
{
public ThreadDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int TID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int TID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.Thread GetModel(int TID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
(2)、SQLServerDAL项目里对这两表操作代码如下:
UserInfoDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.SqlClient;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.SQLServerDAL
{
/// <summary>
/// 数据访问类UserInfoDAL。
/// </summary>
public class UserInfoDAL : IUserInfoDAL
{
public UserInfoDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int UID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int UID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.UserInfo GetModel(int UID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
ThreadDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.OleDb;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.OleDbDAL
{
/// <summary>
/// 数据访问类ThreadDAL。
/// </summary>
public class ThreadDAL : IThreadDAL
{
public ThreadDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int TID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int TID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.Thread GetModel(int TID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
(2)、SQLServerDAL项目里对这两表操作代码如下:
UserInfoDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.SqlClient;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.SQLServerDAL
{
/// <summary>
/// 数据访问类UserInfoDAL。
/// </summary>
public class UserInfoDAL : IUserInfoDAL
{
public UserInfoDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int UID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int UID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.UserInfo GetModel(int UID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
ThreadDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.SqlClient;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.SQLServerDAL
{
/// <summary>
/// 数据访问类ThreadDAL。
/// </summary>
public class ThreadDAL : IThreadDAL
{
public ThreadDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int TID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int TID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.Thread GetModel(int TID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
(3)、OracleDAL项目里对这两表操作代码如下:
UserInfoDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.OracleClient;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.OracleDAL
{
/// <summary>
/// 数据访问类UserInfoDAL。
/// </summary>
public class UserInfoDAL : IUserInfoDAL
{
public UserInfoDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int UID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.UserInfo model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int UID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.UserInfo GetModel(int UID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
ThreadDAL.cs代码如下:
using System;
using System.Data;
using System.Text;
using System.Data.OracleClient;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//请先添加引用
namespace Maticsoft.OracleDAL
{
/// <summary>
/// 数据访问类ThreadDAL。
/// </summary>
public class ThreadDAL : IThreadDAL
{
public ThreadDAL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int TID)
{
//代码略
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.Thread model)
{
//代码略
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int TID)
{
//代码略
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.Thread GetModel(int TID)
{
//代码略
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
//代码略
}
}
}
3、实现抽象工厂模式,建立项目DALFactory
(1)、实现条件外置,通过配置文件来实现对数据访问层的判断,从而访问不同的数据库
在web.config里增加当前数据库访问层信息
<appSettings>
<!--数据访问层程序集名称 -->
<add key="DAL" value="Maticsoft.SQLServerDAL" />
</appSettings>
(2)、在DataAccess.cs类中,通过配置文件和反射来动态创建对象。通过配置文件里的程序集名,决定加载哪个DAL的程序集,动态组合类名来动态创建DAL对象
using System;
using System.Reflection;
using System.Configuration;
namespace Maticsoft.DALFactory
{
/// <summary>
/// Abstract Factory pattern to create the DAL。
/// 如果在这里创建对象报错,请检查web.config里是否修改了<add key="DAL" value="Maticsoft.SQLServerDAL" />。
/// </summary>
public sealed class DataAccess
{
private static readonly string AssemblyPath = ConfigurationManager.AppSettings["DAL"];
public DataAccess()
{ }
//不使用缓存
private static object CreateObjectNoCache(string AssemblyPath, string classNamespace)
{
try
{
object objType = Assembly.Load(AssemblyPath).CreateInstance(classNamespace);
return objType;
}
catch//(System.Exception ex)
{
//string str=ex.Message;// 记录错误日志
return null;
}
}
//使用缓存
private static object CreateObject(string AssemblyPath, string classNamespace)
{
object objType = DataCache.GetCache(classNamespace);
if (objType == null)
{
try
{
objType = Assembly.Load(AssemblyPath).CreateInstance(classNamespace);
DataCache.SetCache(classNamespace, objType);// 写入缓存
}
catch//(System.Exception ex)
{
//string str=ex.Message;// 记录错误日志
}
}
return objType;
}
public static Maticsoft.IDAL.ISysManage CreateSysManage()
{
//方式
//return (Maticsoft.IDAL.ISysManage)Assembly.Load(AssemblyPath).CreateInstance(AssemblyPath+".SysManage");
//方式
string classNamespace = AssemblyPath + ".SysManage";
object objType = CreateObject(AssemblyPath, classNamespace);
return (Maticsoft.IDAL.ISysManage)objType;
}
/// <summary>
/// 创建ThreadDAL数据层接口
/// </summary>
public static Maticsoft.IDAL.IThreadDAL CreateThreadDAL()
{
string ClassNamespace = AssemblyPath + ".ThreadDAL";
object objType = CreateObject(AssemblyPath, ClassNamespace);
return (Maticsoft.IDAL.IThreadDAL)objType;
}
/// <summary>
/// 创建UserInfoDAL数据层接口
/// </summary>
public static Maticsoft.IDAL.IUserInfoDAL CreateUserInfoDAL()
{
string ClassNamespace = AssemblyPath + ".UserInfoDAL";
object objType = CreateObject(AssemblyPath, ClassNamespace);
return (Maticsoft.IDAL.IUserInfoDAL)objType;
}
}
}
4、建立业务逻辑层项目BLL,在BLL项目中添加对IDAL和DALFactory项目的引用。在BLL层中通过DALFactory来创建DAL对象的接口调用,而不关心具体调用哪个DAL对象。
UserInfoBLL.cs的代码如下:
using System;
using System.Data;
using System.Collections.Generic;
using LTP.Common;
using Maticsoft.Model;
using Maticsoft.DALFactory;
using Maticsoft.IDAL;
namespace Maticsoft.BLL
{
/// <summary>
/// 业务逻辑类UserInfoBLL 的摘要说明。
/// </summary>
public class UserInfoBLL
{
private readonly IUserInfoDAL dal = DataAccess.CreateUserInfoDAL();
public UserInfoBLL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int UID)
{
return dal.Exists(UID);
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.UserInfo model)
{
dal.Add(model);
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.UserInfo model)
{
dal.Update(model);
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int UID)
{
dal.Delete(UID);
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.UserInfo GetModel(int UID)
{
return dal.GetModel(UID);
}
/// <summary>
/// 得到一个对象实体,从缓存中。
/// </summary>
public Maticsoft.Model.UserInfo GetModelByCache(int UID)
{
string CacheKey = "UserInfoModel-" + UID;
object objModel = LTP.Common.DataCache.GetCache(CacheKey);
if (objModel == null)
{
try
{
objModel = dal.GetModel(UID);
if (objModel != null)
{
int ModelCache = LTP.Common.ConfigHelper.GetConfigInt("ModelCache");
LTP.Common.DataCache.SetCache(CacheKey, objModel, DateTime.Now.AddMinutes(ModelCache), TimeSpan.Zero);
}
}
catch { }
}
return (Maticsoft.Model.UserInfo)objModel;
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
return dal.GetList(strWhere);
}
/// <summary>
/// 获得数据列表
/// </summary>
public List<Maticsoft.Model.UserInfo> GetModelList(string strWhere)
{
DataSet ds = dal.GetList(strWhere);
return DataTableToList(ds.Tables[0]);
}
/// <summary>
/// 获得数据列表
/// </summary>
public List<Maticsoft.Model.UserInfo> DataTableToList(DataTable dt)
{
List<Maticsoft.Model.UserInfo> modelList = new List<Maticsoft.Model.UserInfo>();
int rowsCount = dt.Rows.Count;
if (rowsCount > 0)
{
Maticsoft.Model.UserInfo model;
for (int n = 0; n < rowsCount; n++)
{
model = new Maticsoft.Model.UserInfo();
if (dt.Rows[n]["UID"].ToString() != "")
{
model.UID = int.Parse(dt.Rows[n]["UID"].ToString());
}
model.UserLogonName = dt.Rows[n]["UserLogonName"].ToString();
model.UserPassword = dt.Rows[n]["UserPassword"].ToString();
model.HeadImg = dt.Rows[n]["HeadImg"].ToString();
model.Email = dt.Rows[n]["Email"].ToString();
model.QICQ = dt.Rows[n]["QICQ"].ToString();
if (dt.Rows[n]["RegistDate"].ToString() != "")
{
model.RegistDate = DateTime.Parse(dt.Rows[n]["RegistDate"].ToString());
}
modelList.Add(model);
}
}
return modelList;
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetAllList()
{
return GetList("");
}
/// <summary>
/// 获得数据列表
/// </summary>
//public DataSet GetList(int PageSize,int PageIndex,string strWhere)
//{
//return dal.GetList(PageSize,PageIndex,strWhere);
//}
}
}
ThreadBLL.cs的代码如下:
using System;
using System.Data;
using System.Collections.Generic;
using LTP.Common;
using Maticsoft.Model;
using Maticsoft.DALFactory;
using Maticsoft.IDAL;
namespace Maticsoft.BLL
{
/// <summary>
/// 业务逻辑类ThreadBLL 的摘要说明。
/// </summary>
public class ThreadBLL
{
private readonly IThreadDAL dal = DataAccess.CreateThreadDAL();
public ThreadBLL()
{ }
/// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(int TID)
{
return dal.Exists(TID);
}
/// <summary>
/// 增加一条数据
/// </summary>
public void Add(Maticsoft.Model.Thread model)
{
dal.Add(model);
}
/// <summary>
/// 更新一条数据
/// </summary>
public void Update(Maticsoft.Model.Thread model)
{
dal.Update(model);
}
/// <summary>
/// 删除一条数据
/// </summary>
public void Delete(int TID)
{
dal.Delete(TID);
}
/// <summary>
/// 得到一个对象实体
/// </summary>
public Maticsoft.Model.Thread GetModel(int TID)
{
return dal.GetModel(TID);
}
/// <summary>
/// 得到一个对象实体,从缓存中。
/// </summary>
public Maticsoft.Model.Thread GetModelByCache(int TID)
{
string CacheKey = "ThreadModel-" + TID;
object objModel = LTP.Common.DataCache.GetCache(CacheKey);
if (objModel == null)
{
try
{
objModel = dal.GetModel(TID);
if (objModel != null)
{
int ModelCache = LTP.Common.ConfigHelper.GetConfigInt("ModelCache");
LTP.Common.DataCache.SetCache(CacheKey, objModel, DateTime.Now.AddMinutes(ModelCache), TimeSpan.Zero);
}
}
catch { }
}
return (Maticsoft.Model.Thread)objModel;
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetList(string strWhere)
{
return dal.GetList(strWhere);
}
/// <summary>
/// 获得数据列表
/// </summary>
public List<Maticsoft.Model.Thread> GetModelList(string strWhere)
{
DataSet ds = dal.GetList(strWhere);
return DataTableToList(ds.Tables[0]);
}
/// <summary>
/// 获得数据列表
/// </summary>
public List<Maticsoft.Model.Thread> DataTableToList(DataTable dt)
{
List<Maticsoft.Model.Thread> modelList = new List<Maticsoft.Model.Thread>();
int rowsCount = dt.Rows.Count;
if (rowsCount > 0)
{
Maticsoft.Model.Thread model;
for (int n = 0; n < rowsCount; n++)
{
model = new Maticsoft.Model.Thread();
if (dt.Rows[n]["TID"].ToString() != "")
{
model.TID = int.Parse(dt.Rows[n]["TID"].ToString());
}
model.Title = dt.Rows[n]["Title"].ToString();
model.UserName = dt.Rows[n]["UserName"].ToString();
if (dt.Rows[n]["ReplyId"].ToString() != "")
{
model.ReplyId = int.Parse(dt.Rows[n]["ReplyId"].ToString());
}
model.Content = dt.Rows[n]["Content"].ToString();
if (dt.Rows[n]["ClickNum"].ToString() != "")
{
model.ClickNum = int.Parse(dt.Rows[n]["ClickNum"].ToString());
}
if (dt.Rows[n]["ReplyNum"].ToString() != "")
{
model.ReplyNum = int.Parse(dt.Rows[n]["ReplyNum"].ToString());
}
if (dt.Rows[n]["WriteDate"].ToString() != "")
{
model.WriteDate = DateTime.Parse(dt.Rows[n]["WriteDate"].ToString());
}
modelList.Add(model);
}
}
return modelList;
}
/// <summary>
/// 获得数据列表
/// </summary>
public DataSet GetAllList()
{
return GetList("");
}
/// <summary>
/// 获得数据列表
/// </summary>
//public DataSet GetList(int PageSize,int PageIndex,string strWhere)
//{
//return dal.GetList(PageSize,PageIndex,strWhere);
//}
#endregion 成员方法
}
}
基于工厂模式的三层结构模型图:
总结:
1、IDAL项目是一系列对不同表“功能”的声明,没有实现细节。对于每个表都建立一个此表的接口,声明对此表的一系列功能操作。
如上列用户表UserInfo和帖子表Thread分别建立接口:IUserInfoDAL,IThreadDAL接口
2、OleDbDAL,OracleDAL,SQLServerDAL三个针对不同数据库操作的项目,每个项目里,对数据库的每个表都要建立一个类,此类必须实现关于此表操作的接口(此表操作的接口在IDAL里定义)。这样把不同数据库具体的实现分开,方法的规则必须以IDAL接口所定义的一致。相当于所有的数据访问层实现封装起来,暴露在外面的就是IDAL接口,被提供使用。
如上例在OleDbDAL,OracleDAL,SQLServerDAL的每个项目里,都有对用户表UserInfo和帖子表Thread的操作,并实现对应的接口
public class ThreadDAL:IThreadDAL
public class UserInfoDAL:IUserInfoDAL
3、DALFactory根据Web.config所指定的程序集名称,通过反射来调用不同的数据库操作的访问类。
如上例:
private static readonly string AssemblyPath = ConfigurationManager.AppSettings["DAL"];
private static object CreateObjectNoCache(string AssemblyPath, string classNamespace)
{
try
{
object objType = Assembly.Load(AssemblyPath).CreateInstance(classNamespace);
return objType;
}
catch//(System.Exception ex)
{ return null; }
}
CreateObjectNoCache()方法根据程序集名(含命名空间路径)和类名(含命名空间路径)来动态创建对象。
例如在此工厂里,要创建用户表UserInfo操作的对象方法如下:
public static Maticsoft.IDAL.IUserInfoDAL CreateUserInfoDAL()
{
string ClassNamespace = AssemblyPath + ".UserInfoDAL";
object objType = CreateObject(AssemblyPath, ClassNamespace);
return (Maticsoft.IDAL.IUserInfoDAL)objType;
}
例如在此工厂里,要创建帖子表Thread操作的对象方法如下:
public static Maticsoft.IDAL.IThreadDAL CreateThreadDAL()
{
string ClassNamespace = AssemblyPath + ".ThreadDAL";
object objType = CreateObject(AssemblyPath, ClassNamespace);
return (Maticsoft.IDAL.IThreadDAL)objType;
}
4、BLL调用DALFactory工厂来决定要创建哪个表的数据访问对象的接口。
例如,针对用户表UserInfo和帖子表Thread调用代码如下:
private readonly IUserInfoDAL dal = Maticsoft.DALFactory.DataAccess.CreateUserInfoDAL();
private readonly IThreadDAL dal = DataAccess.CreateThreadDAL();
返回给BLL的是IDAL对象。