数据访问层的使用方法
一、操作语句部分
简单的说就是传入一个操作语句,然后接收返回值就可以了。为了简化代码和提高效率,所以呢设置了五种返回类型。
1、 DataSet
函数名称:DateSet ds = RunSqlDataSet(查询语句)
传入一个查询语句(多条select 的查询语句),然后接收返回值就可以了。
没有记录返回 null
2、 DataTable
函数名称:DateTable dt = RunSqlDataTable(查询语句)
传入一个查询语句(一条select 的查询语句),然后接收返回值就可以了。
没有记录返回 null
3、 DataRow
函数名称:DataRow dr = RunSqlDataRow(查询语句)
传入一个查询语句(一条select 的查询语句),然后接收返回值就可以了。
没有记录返回 null
4、 String[]
函数名称:string[] str = RunSqlStrings (查询语句)
传入一个查询语句(一条select 的查询语句),然后接收返回值就可以了。
没有记录返回 null
5、 String
函数名称:string str = RunSqlGetID (查询语句)
传入一个查询语句(一条select 的查询语句),然后接收返回值就可以了。
没有记录返回 null
6、 Null
函数名称:RunSql (操作语句)
传入一个操作语句(insert 、update、delete的操作语句)。
说明:参数都是字符串型的。
二、存储过程部分
简单的说就是和查询语句的很类似了,只不过多了个存储过程的参数。
1、 DataSet
函数名称:DateSet ds = RunStoreDataSet(存储过程的名称)
传入存储过程的名称,然后接收返回值。
没有记录返回 null
2、 DataTable
函数名称:DateTable dt = RunStoreDataTable(存储过程的名称)
传入存储过程的名称,然后接收返回值。
没有记录返回 null
3、 Null
函数名称:RunStore (存储过程的名称)
传入存储过程的名称。
三、存储过程的参数(1)
如果没有参数的话,那么存储过程的用法和查询语句的也就一样了。但是呢,大多数的存储过程都是有参数的,不过有了参数我们也不怕!
我们可以用addNewParameter方法来添加存储过程的参数。不用像SQLHelp那样麻烦,还得传入一个Parameter的对象。我们直接调用数据访问层的方法就可以了。
这里通过函数重载的方式来区分不同的数据类型。以C#里的数据类型为标准,对应SQL里面的数据类型。
1、 int型的参数
这里对应三个SQL Server的数据类型:int、tinyint、smallint
函数名称:addNewParameter(string ParameterName,int ParameterValue)
ParameterName:参数名称。
ParameterValue:参数值。
2、 bit型的参数
这里对应一个SQL Server的数据类型:bit
函数名称:addNewParameter(string ParameterName,bool ParameterValue)
ParameterName:参数名称。
ParameterValue:参数值。
3、 double型的参数
这里对应两个SQL Server的数据类型:float、real
函数名称:addNewParameter(string ParameterName,double ParameterValue )
ParameterName:参数名称。
ParameterValue:参数值。
4、 string型的参数
这里对应七个SQL Server的数据类型:char、nchar、varchar、nvarchar、uniqueidentifier、smalldatetime、datetime
函数名称:addNewParameter(string ParameterName,string ParameterValue,int size)
ParameterName:参数名称。
ParameterValue:参数值。
Size: 参数的大小。
5、 ntext型的参数
这里对应两个SQL Server的数据类型:ntext、text
函数名称:addNewParameter(string ParameterName,string ParameterValue)
ParameterName:参数名称。
ParameterValue:参数值。
6、 金额型的参数
这里对应三个SQL Server的数据类型:decimal、smallmoney、money
函数名称:addNewParameter(string ParameterName,decimal ParameterValue)
ParameterName:参数名称。
ParameterValue:参数值。
7、 说明
还有二进制类型的没有处理。忘记要用C#的哪个类型来对应了。
这里添加的参数都是输入型(input)的,如果想设置输出型的参数请看下面。
四、存储过程的参数(2)
这里讲述如何设置输出型(output)的参数,以及如何修改参数值、取值和清除参数
1、 设置输出型参数
函数名称:addNewParameter(string ParameterName,ZDIC.ParameterKind kind)
ParameterName:参数名称。
Kind:参数类型。
2、 获取参数的返回值
函数1名称:getParameter(int ParameterIndex)
ParameterIndex:参数的序号。
通过参数的序号来返回参数值。
函数2名称:getParameter(string ParameterName)
ParameterName:参数的名称。
通过参数名称来返回参数值。
3、 修改参数值
函数1名称:setParameter(int ParameterIndex,string parameterValue)
ParameterIndex:参数的序号。
通过参数的序号来修改参数值。
函数2名称:setParameter(string ParameterName,string parameterValue)
ParameterName:参数的名称。
通过参数名称来修改参数值。
4、 清除参数
函数名称:ClearParameter()
执行一下就行除了。
五、异常处理
这里并不向上层抛出异常,取代的是给ErrorMsg属性赋值。如果程序正常执行,则ErrorMsg==”0”表示没有发生异常;否则ErrorMsg的内容就是错误描述。
错误描述包括三个部分:函数名称,执行的查询语句(存储过程)和系统给出的错误信息。这样呢就很容易发现出错的地方,尤其是在使用查询语句的时候。
六、错误日志
在发生异常的时候,会自动记录错误信息,以便日后的维护和修改错误。
错误日志以文本文件的形式存放在 /log文件夹下面,文件名是yyyyMMdd的格式。
为什么用文本文件而不用数据库?因为一般在正式使用后发生的异常大多都是由于数据库造成的,所以很有可能在发生异常之后已经无法再向数据库里写信息了。而向文本文件里写信息一般是不会出错的。
七、连接字符串及Connection对象
连接字符串是从 Connection.dll 里面读取的,其目的是适应连接字符串的各种变化。比如是否加密,用什么算法加密;连接字符串存放在什么地方?web.config、DLL、注册表或者其他的什么地方。引用Conection.dll后就可以很轻松的应对以上的这些要求。
八、事务处理
利用 Connection.BeginTransaction 等方法实现事务。没有作严格的测试,因为目前还没有用到。
九、更换数据库
这里是针对SQL Server 数据库做的处理,也就是对SqlClinet进行的封装。如果更换数据库的话,那么只需要把Sql字样换成对应的数据库的表示就可以了。其他的作一些适当的调整就可以了。
十、使用示例
以新闻系统为例
1、 用查询语句的方式获取新闻列表,然后绑定Repeater控件。
DataAccessLayer dal = new DataAccessLayer();
Rpt.DataSource = dal.RunSqlDataTable("select NewsID,addedDate,title from news ");
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
Rpt.DataBind();
2、 用存储过程的方式获取新闻列表,然后绑定Repeater控件。
DataAccessLayer dal = new DataAccessLayer();
Rpt.DataSource = dal.RunStoreDataTable("Proc_News_list");
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
Rpt.DataBind();
3、 用string[]的方式获取一条新闻纪录。然后给Label控件赋值。
DataAccessLayer dal = new DataAccessLayer();
string sql = "select Title,AddedDate,Content from News where NewsID=" + NewsID
string[] Infos = dal.RunSqlStrings(sql);
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
if (Infos == null)
{
Response.Write("没有这条新闻!");
Response.End();
}
Lbl_Title.Text = Infos[0];
Lbl_AddedDate.Text = Infos[1].Split(' ')[0];
Lbl_Content.Text = Infos[2];
4、 用DataRow的方式获取一条新闻纪录。然后给Label控件赋值。
DataAccessLayer dal = new DataAccessLayer();
string sql = "select Title,AddedDate,Content from News where NewsID=" + NewsID
DataRow Infos = dal.RunSqlDataRow(sql);
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
if (Infos == null)
{
Response.Write("没有这条新闻!");
Response.End();
}
Lbl_Title.Text = Infos["Title"].ToString();
Lbl_AddedDate.Text = Infos["AddedDate"] .ToString().Split(' ')[0];
Lbl_Content.Text = Infos["Content"] .ToString();
5、 用InsertDataStr和UpdateData实现添加、修改新闻。同时用RunSqlExists判断新闻标题是否重复。
//判断是修改还是添加
bool isAdd = false;
if (DG.SelectedIndex == -1) //利用DataGrid的状态来判断是添加还是修改。
isAdd = true;
//设定字段。这里一定要用一个数组来表示,这是 InsertDataStr 函数的参数的要求!
string[] str1 = new string[2];
str1[0] = "title";
str1[1] = "Content";
//获取用户输入的信息,并且过滤危险字符
//这里一定要用一个数组来表示,这是 InsertDataStr 函数的参数的要求!
string[] str = new string[2];
str[0] = this.Txt_Title.Text.Trim().Replace("'","");
str[1] = this.Txt_Content.Text.Trim().Replace("'","");
#region 数据验证
if (str[0].Length == 0 )
{
Page.RegisterStartupScript("a",Functions.myAlert("请填写新闻标题!"));
return;
}
DataAccessLayer dal = new DataAccessLayer();
if (isAdd)
{
if (dal.RunSqlExists("select top 1 '1' from news where title='" + str[0] + "'" ))
{
Page.RegisterStartupScript("a",Functions.myAlert("已经有这个新闻标题了!"));
return;
}
}
else
{
if (dal.RunSqlExists("select top 1 '1' from news where title='" + str[0] + "' and NewsID <>" + DG.SelectedItem.Cells[0].Text))
{
Page.RegisterStartupScript("a",Functions.myAlert("已经有这个新闻标题了!"));
return;
}
}
#endregion
if (isAdd)
//添加新闻
dal.InsertDataStr("News",str1,str);
else
//修改新闻
dal.UpdateData("News",str1,str," NewsID=" + DG.SelectedItem.Cells[0].Text);
//检查是否出现异常
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
if (isAdd)
//添加成功。进行相应处理
else
//修改成功。进行相应处理
6、 用RunStore 用的方式添加修改新闻
//判断是修改还是添加
bool isAdd = false;
if (DG.SelectedIndex == -1) //利用DataGrid的状态来判断是添加还是修改。
isAdd = true;
//获取用户输入的信息,存储过程的方式就不用过滤了
string NewsTitle = this.Txt_Title.Text.Trim();
string NewsContent = this.Txt_Content.Text;
// 数据验证
if (str[0].Length == 0 )
{
Page.RegisterStartupScript("a",Functions.myAlert("请填写新闻标题!"));
return;
}
//标题是否重复的判断由存储过程来实现
DataAccessLayer dal = new DataAccessLayer();
//添加存储过程的参数
dal.addNewParameter("@title",NewsTitle,100);
dal.addNewParameter("@Content",NewsContent);
//output型的参数
dal.addNewParameter("@ReturnMsg",ParameterKind.NVarChar );
if (!isAdd)
//修改新闻,需要给 @NewsID 负值。
dal.addNewParameter("@NewsID",Int32.Parse(DG.SelectedItem.Cells[0].Text))
//执行存储过程
dal.RunStore("Proc_News_ModData");
//检查是否出现异常
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
string err = dal.getParameter("@ReturnMsg");//获取参数的返回值
if (isAdd)
{//添加状态
if (err.Length > 1)
{
//显示存储过程里面返回的错误信息,比如新闻标题重名等。
}
else
{
//添加成功
SetFormEmpty();
}
}
else
{//修改状态
if (err.Length > 1)
{
//显示存储过程里面返回的错误信息,比如新闻标题重名等。
}
else
{
//修改成功
SetFormVisible(false);
}
}
7、 用RunSql 删除新闻
DataAccessLayer dal = new DataAccessLayer();
dal.RunSql("delete from News where NewsID=" + e.Item.Cells[0].Text);
//检查是否出现异常
if (dal.ErrorMsg.Length > 2 )
{
Response.Write(dal.ErrorMsg ); //输出错误信息
return;
}
8、 说明
除了添加修改的地方,代码都是非常简洁的。可以说只用了一行就达到了目的。由于省去了实体层,数据访问层也变成了DLL类库,所以说呢,从表面上看程序的结构就变成了一层结构了,也就是说只需写这些代码就可以实现一个模块的基本功能了。
再来看看添加修改的地方。虽然代码好像多了一点,但是合并了添加、修改的共同的地方,减少了三分之一的代码。可能会比三层结构的UI层的代码量多一些,但是没有实体层、业务逻辑层和数据访问层的代码。重整体上来说减少了三倍的代码量。
修改上也是很方便的。如果要修改字段名称的话,只需要修改str1数组里对应的值就可以了;添加字段呢,只需要增加str1和str数组的大小,并负值就可以了。省去了其他层的修改(因为根本就没有在其他的地方写代码!)