如何打造自己的数据访问层二

当我们通过上篇《打造自己的数据访问层一》已了解了.NET对数据库操作的基本原理,并就Ado.net对象的使用提出了几点疑问:

1、如何由系统来判断数据库型。

2、如何消除这些重复代码。

而上篇中也提出了一种解决思路,对ADO.NET对象进行封装,具体应该如何实施?

1、需要一个对象,该对象用于建立内存表与物理表的之间映射关系,解决数据查询、更新操作,形成了数据映射对象,定义为DataMapping。

2、每一个映射对象只与一张物理建立映射关系,如果有多个这样的对象同时操作,如何解决?这时就需要另一个对象,用于添加映射对象集合,打包映射对象操作,形成了数据执行者,定义为DataExecutor。

想想看,只需要这两个基本对象,就可以形成简单的数据访问层了。

先实现DataMapping,它应具备如下功能。

1、需要知道物理表的信息,表名、主键集、字段集。

2、需要知道映射的是什么类型的数据库,MSSql数据库、Oracle数据库、MySql数据库或者其他类型的数据库。

3、可查询数据,即填充内存表。

4、可更新数据,并且可设置更新操作方式。

5、可加入到事务中去。

根据上述功能,可初步设计出的DataMapping类:

publicclass DataMapping
{
public DataMapping()
{ }

///<summary>
/// 填充数据集
///</summary>
publicvoid Fill()
{

}

///<summary>
/// 设置更新命令
///</summary>
publicvoid SetCommands()
{

}

///<summary>
/// 设置数据提交事务
///</summary>
publicvoid SetTransaction()
{

}

///<summary>
/// 提交数据
///</summary>
publicbool Update()
{

}

///<summary>
/// 更新列名
///</summary>
publicstring Columns
{
get
{
return columns;
}
set
{
columns
= value;
}
}
privatestring columns ="";

///<summary>
/// 主键名
///</summary>
publicstring KeyColumns
{
get
{
return keyColumns;
}
set
{
keyColumns
= value;
}
}
privatestring keyColumns ="";

///<summary>
/// 表名
///</summary>
publicstring TableName
{
get
{
return tableName;
}
set
{
tableName
= value;
}
}
privatestring tableName ="";
}

再来实现DataExecutor类,它应具备的功能:

1、应该知道执行什么类型的数据库操作。

2、可以添加映射对象。

3、可以进行数据提交。

如何来知道执行的数据库类型,我们可以定义具体的执行者,比如MSSql执行者、Oracle执行者、MySql执行者。

可以初步设计出DataExecutor类
 

publicabstractclass DataExecutor
{
private IList<DataMapping> lisDataMappings =new List<DataMapping>();

///<summary>
/// 添加数据映射对象
///</summary>
publicvoid AddDataMapping(DataMapping map)
{

}

///<summary>
/// 更新数据
///</summary>
publicbool Update()
{

}
}

publicclass MSSqlExecutor : DataExecutor
{

}

publicclass OracleExecutor : DataExecutor
{

}

publicclass MySqlExecutor : DataExecutor
{

}

准备就绪,开始行具体设计。

先从DataMapping的Fill方法入手,看看它是如何查询数据的。

publicvoid Fill(string sqlText, string tableName, DataSet ds)
{
IDbConnection conn
= 具体的数据连接对象;
IDbDataAdapter dataAdapter
= 具体的数据适配对象;
IDbCommand cmd
= 具体的命令对象;
cmd.Connection
= conn;
cmd.CommandText
= sqlText;
dataAdapter.SelectCommand
= cmd;
((DbDataAdapter)dataAdapter).Fill(ds, tableName);
}

问题出来了,这里出现了具体的对象,如何得到这些对象?

前面我们设计了MSSqlExecutor类,它已经知道具体的数据库类型,所以它也应该知道进行数据操作的具体的对象,DataMapping类是否可以引用该它,从而通过它来获取数据操作对象,因此,可以MSSqlExecutor类及DataMapping类进行修改,使DataMapping对MSSqlExecutor类产生依赖关系;这只是对MSSql数据库进行操作,现要改变数据库对象为Oracle了,DataMapping类应该也需要对OracleExecutor类产生依赖关系。

因此,这里可以设计一个接口,用于获取具体对象:

///<summary>
/// 映射执行接口
///</summary>
publicinterface IMappingExecute
{
///<summary>
/// 获取连接对象
///</summary>
IDbConnection GetConn();

///<summary>
/// 获取数据适配器
///</summary>
IDbDataAdapter GetDataAdapter();

///<summary>
/// 获取命令对象
///</summary>
IDbCommand GetCommand();

///<summary>
/// 获取命令参数
///</summary>
IDbDataParameter GetDataParameter(string col);

///<summary>
/// 获取命令参数
/// 数据库之间的命令参类是不一样的
/// MMSql是“@” + 列名,Oracle是 “:” + 列名,MySql是 “?” + 列名
///</summary>
string GetSourceColumn(string col);
}

改造后的MSSqlExecutor类为:

publicclass MSSqlExecutor : DataExecutor, IMappingExecute
{
}

改造后的DataMapping类为:

publicclass DataMapping
{
private IDbConnection conn =null;
private IDbDataAdapter dataAdapter =null;

///<summary>
/// 映射执行对象
///</summary>
public IMappingExecute ExecuteObject
{
set
{
executeObj
= value;
conn
= executeObj.GetConn();
}
}
private IMappingExecute executeObj;

///<summary>
/// 填充数据集
/// 参数:查询语句
/// 参数:内存表名
///</summary>
publicvoid Fill(string sqlText, string tableName, DataSet ds)
{
dataAdapter
= executeObj.GetDataAdapter();
IDbCommand cmd
= executeObj.GetCommand();
cmd.Connection
= conn;
cmd.CommandText
= sqlText;
dataAdapter.SelectCommand
= cmd;
((DbDataAdapter)dataAdapter).Fill(ds, tableName);
}
}

到此为止,查询功能算是完成了,接下来该实现更新功能了,从SetCommands入手,以新增操作为例:

 

///<summary>
/// 设置更新命令
///</summary>
publicvoid SetCommands(DataCommandType commandType, DataSet ds)
{

if ((commandType & DataCommandType.Insert) == DataCommandType.Insert)
{
CreateInsertCommand(ds);
}

if ((commandType & DataCommandType.Update) == DataCommandType.Update)
{
CreateUpdateCommand(ds);
}

if ((commandType & DataCommandType.Delete) == DataCommandType.Delete)
{
CreateDeleteCommand(ds);
}
}


///<summary>
/// 生成新增命令及SQL语句
///</summary>
privatevoid CreateInsertCommand(DataSet ds)
{
IList
<string> lisColumns = GetColumns(ds);
StringBuilder sbCol
=new StringBuilder();
StringBuilder sbVal
=new StringBuilder();
foreach (string col in lisColumns)
{
sbCol.AppendFormat(
", {0}", col);
sbVal.AppendFormat(
", {0}", executeObj.GetSourceColumn(col));
}

sbCol.Remove(
0, 2);
sbVal.Remove(
0, 2);
string sqlText =string.Format("INSERT INTO {0} ({1}) VALUES ({2})", tableName, sbCol.ToString(), sbVal.ToString());
IDbCommand cmd
= executeObj.GetCommand();
cmd.Connection
= conn;
cmd.CommandText
= sqlText;
SetCommandParams(cmd, lisColumns);
dataAdapter.InsertCommand
= cmd;
}

///<summary>
/// 获取列字段集
///</summary>
private IList<string> GetColumns(DataSet ds)
{
IList
<string> lisColumns =new List<string>();
if (columns !="*")
{
string[] sltCol = columns.Split(',');
foreach (string col in sltCol)
{
lisColumns.Add(col.Trim());
}
}
else
{
DataTable dt
= ds.Tables[tableName];
foreach (DataColumn dc in dt.Columns)
{
lisColumns.Add(dc.ColumnName);
}
}

return lisColumns;
}

 
更新操作非常简单,就是在上一篇的数据操作原理的基础上动态生成了查询语句及参数绑定,不多做解释。 

其中DataCommandType为自定义枚举类型:

///<summary>
/// 数据操作命令类型
///</summary>
publicenum DataCommandType
{
///<summary>
/// 新增
///</summary>
Insert =1,

///<summary>
/// 修改
///</summary>
Update =2,

///<summary>
/// 删除
///</summary>
Delete =4
}

更新完后进行数据提交:

///<summary>
/// 提交数据
///</summary>
publicbool Update(DataSet ds)
{
return ((DbDataAdapter)dataAdapter).Update(ds, tableName) >0;
}

至此,数据更新操作也已经完成,***再看看数据执行者是如何进行批量提交。

这里产生的***个问题是,什么时候数据执行者会人将映射对象加入到集合中来,其中一种方法是在DataMapping设置更新的时候自己加入到集合去。

因此, 映射执行接口得多添加一个方法,用于新增映射对象:

///<summary>
/// 添加数据映射对象
///</summary>
void AddDataMapping(DataMapping map);

 

修改SetCommand方法:

///<summary>
/// 设置更新命令
///</summary>
publicvoid SetCommands(DataCommandType commandType, DataSet ds)
{
//设置更新事件时添加映射对象
executeObj.AddDataMapping(this);
}

现在执行者中已经存在了,可以进行***的数据提交:

///<summary>
/// 更新数据
///</summary>
publicbool Update(DataSet ds)
{
using (conn)
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}

IDbTransaction transaction
= conn.BeginTransaction(IsolationLevel.ReadCommitted);
foreach (DataMapping map in lisDataMappings)
{
map.SetTransaction(transaction);
}

try
{
foreach (DataMapping map in lisDataMappings)
{
map.Update(ds);
}

transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
thrownew System.Exception(ex.Message);
}
}

returntrue;
}

//DataMapping类设置事务
///<summary>
/// 设置数据提交事务
///</summary>
publicvoid SetTransaction(IDbTransaction transaction)
{
if (dataAdapter.InsertCommand !=null)
{
dataAdapter.InsertCommand.Transaction
= transaction;
}

if (dataAdapter.UpdateCommand !=null)
{
dataAdapter.UpdateCommand.Transaction
= transaction;
}

if (dataAdapter.DeleteCommand !=null)
{
dataAdapter.DeleteCommand.Transaction
= transaction;
}
}

 
到些为止,我们自己的数据访问层功能已基本完成,但是,我们要如何对其进行调用,现在的方式真能方便的让我们进行调用吗?答案是否定的。
 

暂且至此为止,下一篇我们再进行***的收尾工作,并最终打造成符合自己需求的数据访问层

 

原文链接:http://www.cnblogs.com/FlySoul/archive/2011/05/04/2036953.html

【编辑推荐】

  1. 晒晒我的通用数据访问层
  2. 几步走,教你创建简单访问数据库方法
  3. 一句代码实现批量数据绑定 下
  4. 一步一步设计你的数据库1
  5. 不重复随机数列生成算法

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/290290.html<

(0)
运维的头像运维
上一篇2025-05-19 03:51
下一篇 2025-05-19 03:52

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注