使用强类型DataSet创建高效的数据访问层:存储过程输出参数的使用
Asp.net2.0中可方便地使用强类型DataSet来创建数据访问层,该方法甚至可自动生成Select、Update、Insert、Delete方法及其存储过程,但该方法自动生成的更新数据库的存储过程只能针对一个表的操作,而且往往都比较简单。现举一个简单的例子,我们插入一条记录时要首先检查数据库中是否存在该记录,如不存在该记录,才进行插入操作。为完成上述操作,很多程序员往往都是通过两次访问数据库来完成,第一次是先检查是否存在该记录,如不存在,才在第二次访问数据库中执行插入语句,这种方法效率的低下自不用多说。下面的例子在创建DataSet时使用了输出参数,并根据输出参数的值来判断该记录是否存在,并在记录未存在时就执行相应的插入操作。所有操作只需一次访问数据库。通过上面这个简单的例子来了解强类型DataSet中输出参数的使用。首先创建存储过程,对应的存储过程如下:
然后创建Dataset,对应的Dataset见下图:

注意其中Ticket表中的IsExist字段,该字段的具体属性可参考下图:
1
CREATE PROCEDURE dbo.Ticket_InsertTicket
2
(
3
@IsExist BIT OUTPUT,
4
@StartStation nvarchar(20),
5
@EndStation nvarchar(50),
6
@Price money,
7
@LowDiscount tinyint,
8
@HighDiscount tinyint,
9
@IsInLand bit,
10
@Continent nvarchar(20) = NULL
11
)
12
AS
13
SET NOCOUNT OFF;
14
IF EXISTS ( SELECT ID FROM [Ticket] WHERE ( [StartStation]=@StartStation AND [EndStation]=@EndStation ) )
15
BEGIN
16
SET @IsExist = 1
17
RETURN
18
END
19
ELSE
20
BEGIN
21
INSERT INTO [Ticket] ([StartStation], [EndStation], [Price], [LowDiscount], [HighDiscount], [IsInLand], [Continent]) VALUES (@StartStation, @EndStation, @Price, @LowDiscount, @HighDiscount, @IsInLand, @Continent);
22
SELECT ID, StartStation, EndStation, StartStation + '至' + EndStation AS Line, Price,
23
LowDiscount, HighDiscount, CAST(LowDiscount AS NVARCHAR(4))+'至'+CAST(HighDiscount AS NVARCHAR(4))+'折' AS Discount, IsInLand, Continent
24
FROM Ticket WHERE (ID = SCOPE_IDENTITY())
25
END
26
GO
27
该存储过程不用详细介绍,只需了解@IsExist为输出参数,并且如已存在相同的StartStation和EndStation记录,则不执行插入操作,@IsExist值为1,否则执行相应的插入操作,@IsExist值为0。
CREATE PROCEDURE dbo.Ticket_InsertTicket2
(3
@IsExist BIT OUTPUT,4
@StartStation nvarchar(20),5
@EndStation nvarchar(50),6
@Price money,7
@LowDiscount tinyint,8
@HighDiscount tinyint,9
@IsInLand bit,10
@Continent nvarchar(20) = NULL11
)12
AS13
SET NOCOUNT OFF;14
IF EXISTS ( SELECT ID FROM [Ticket] WHERE ( [StartStation]=@StartStation AND [EndStation]=@EndStation ) )15
BEGIN 16
SET @IsExist = 117
RETURN18
END19
ELSE20
BEGIN21
INSERT INTO [Ticket] ([StartStation], [EndStation], [Price], [LowDiscount], [HighDiscount], [IsInLand], [Continent]) VALUES (@StartStation, @EndStation, @Price, @LowDiscount, @HighDiscount, @IsInLand, @Continent);22
SELECT ID, StartStation, EndStation, StartStation + '至' + EndStation AS Line, Price, 23
LowDiscount, HighDiscount, CAST(LowDiscount AS NVARCHAR(4))+'至'+CAST(HighDiscount AS NVARCHAR(4))+'折' AS Discount, IsInLand, Continent24
FROM Ticket WHERE (ID = SCOPE_IDENTITY())25
END26
GO27

然后创建Dataset,对应的Dataset见下图:

注意其中Ticket表中的IsExist字段,该字段的具体属性可参考下图:
配置好Dataset后,下一步是在BLL层中对上述@IsExist参数的调用过程,下面是BLL层插入方法的代码,注意其中的一个ref类型的参数IsExist,调用DAL后的对应结果将通过该参数返回给界面层:
1
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]
2
public bool InsertTicket(ref bool IsExist, string StartStation, string EndStation,
3
decimal Price, byte LowDiscount, byte HighDiscount,bool IsInLand,string Continent)
4
{
5
dsForeground.TicketDataTable dtTable = new dsForeground.TicketDataTable();
6
dsForeground.TicketRow dtRow = dtTable.NewTicketRow();
7
8
dtRow.StartStation = StartStation.Trim();
9
dtRow.EndStation = EndStation.Trim();
10
dtRow.Price = Price;
11
dtRow.LowDiscount = LowDiscount;
12
dtRow.HighDiscount = HighDiscount;
13
dtRow.IsInLand = IsInLand;
14
if (IsInLand == false)
15
{
16
if (string.IsNullOrEmpty(Continent))
17
throw new ApplicationException(Resources.Resource.ContinentInputError);
18
else
19
dtRow.Continent = Continent.Trim();
20
}
21
else
22
dtRow.Continent = string.Empty;
23
dtTable.AddTicketRow(dtRow);
24
int affectedRow = Adapter.Update(dtRow);
25
//获取执行结果
26
IsExist = dtRow.IsExist;
27
return affectedRow == 1;
28
}
29
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]2
public bool InsertTicket(ref bool IsExist, string StartStation, string EndStation,3
decimal Price, byte LowDiscount, byte HighDiscount,bool IsInLand,string Continent)4
{5
dsForeground.TicketDataTable dtTable = new dsForeground.TicketDataTable();6
dsForeground.TicketRow dtRow = dtTable.NewTicketRow();7

8
dtRow.StartStation = StartStation.Trim();9
dtRow.EndStation = EndStation.Trim();10
dtRow.Price = Price;11
dtRow.LowDiscount = LowDiscount;12
dtRow.HighDiscount = HighDiscount;13
dtRow.IsInLand = IsInLand;14
if (IsInLand == false)15
{16
if (string.IsNullOrEmpty(Continent))17
throw new ApplicationException(Resources.Resource.ContinentInputError);18
else19
dtRow.Continent = Continent.Trim();20
}21
else22
dtRow.Continent = string.Empty;23
dtTable.AddTicketRow(dtRow);24
int affectedRow = Adapter.Update(dtRow);25
//获取执行结果26
IsExist = dtRow.IsExist;27
return affectedRow == 1; 28
}29

界面层:本实例使用了FormView来作为记录的插入的容器,要判断插入操作的详细信息,可在插入后的事件代码中执行下面的语句,根据IsExist的值可判断究竟是插入成功还是记录已经存在而未执行插入操作。
1
protected void ObjectDS_InLandManage_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
2
{
3
//此处代码略
4
IsExist = Convert.ToBoolean(e.OutputParameters["IsExist"]);
5
//此处代码略
6
}
7
protected void ObjectDS_InLandManage_Inserted(object sender, ObjectDataSourceStatusEventArgs e)2
{3
//此处代码略4
IsExist = Convert.ToBoolean(e.OutputParameters["IsExist"]);5
//此处代码略 6
}7

总结:在强类型Dataset中使用存储过程输出参数,可获取复杂的存储过程的执行结果,在一次访问数据库时就可完成尽可能多的工作,提高程序访问数据库操作的效率和性能。

浙公网安备 33010602011771号