在我前面很多篇關(guān)于框架設(shè)計和介紹的文章里面,大多數(shù)都是利用框架提供的基礎(chǔ)性API進行各種的操作,包括增刪改查、分頁等各種實現(xiàn)和其衍生的實現(xiàn),而這些實現(xiàn)絕大多數(shù)是基于SQL的標準操作實現(xiàn)的,由于框架的底層是利用了微軟企業(yè)庫Enterprise Library,因此框架也是很好的支持存儲過程的各種調(diào)用,不過由于整體性和數(shù)據(jù)庫遷移方面的考慮,建議一般使用標準的SQL操作而已,這樣能夠很大程度上保證數(shù)據(jù)庫可以很平滑過渡到其他數(shù)據(jù)庫,如Access、SQLite等單機版數(shù)據(jù)庫。但是,有時候我們提供對存儲過程的支持也是十分必要的,有些業(yè)務(wù)可能就只是固定在某種特定的數(shù)據(jù)庫上跑,如SQLServer、Oracle等這些支持存儲過程的關(guān)系型數(shù)據(jù)庫,有些業(yè)務(wù)可能還真的需要存儲過程的整體性的封裝;基于這個原因,我撰寫了這篇文章,力求從較為全面的角度上闡述存儲過程的編寫、實現(xiàn)和演化提煉方面做一個介紹。
1、SQLServer存儲過程的編寫
雖然存儲過程一般用于處理一些復(fù)雜的邏輯關(guān)系或者報表內(nèi)容,不過為了介紹方便,我們從幾個較為基礎(chǔ)的操作進行介紹。
我們以一個客戶表來進行對應(yīng)的存儲過程來介紹,先介紹客戶表T_Customer的表定義。

它的SQLServer腳本如下所示
create table dbo.T_Customer (
ID nvarchar(50) not null,
Name nvarchar(50) null,
Age int null,
Creator nvarchar(50) null,
CreateTime datetime null,
constraint PK_T_CUSTOMER primary key (ID)
)
為了介紹存儲過程的編寫,我們以這個表的相關(guān)操作的存儲過程來進行介紹,存儲過程一般可以分為下面幾種情況。
1)提供執(zhí)行處理,可對執(zhí)行結(jié)果進行反饋
這種情況常??梢砸姷剑缈梢詫Σ迦?、更新、刪除等操作進行處理,并獲得執(zhí)行的結(jié)果,下面是這兩種存儲過程的代碼。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:插入數(shù)據(jù)到表中
------------------------------------
CREATE PROCEDURE dbo.T_Customer_Insert
(
@ID varchar(50),
@Name varchar(50) ,
@Age int
)
AS
begin tran
Insert into dbo.T_Customer( ID,Name,Age ) Values( @ID,@Name,@Age )
if @@error!=0
begin
rollback
end
else
begin
commit
end
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,修改表中的數(shù)據(jù)
------------------------------------
CREATE PROCEDURE dbo.T_Customer_UpdateByID
(
@ID varchar(50),
@Name varchar(50) ,
@Age int
)
AS
begin tran
Update dbo.T_Customer Set Name=@Name,Age=@Age Where ID= @ID
if @@error!=0
begin
rollback
end
else
begin
commit
end
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,刪除表的記錄
------------------------------------
CREATE PROCEDURE dbo.T_Customer_DeleteByID
(
@ID varchar(50)
)
AS
begin tran
Delete From dbo.T_Customer where ID=@ID
if @@error!=0
begin
rollback
end
else
begin
commit
end
go
2)提供執(zhí)行處理,獲得一個或者多個返回性參數(shù),并可對執(zhí)行結(jié)果進行反饋。
基于上面的處理方式,我們可能還有一種情況,就是需要執(zhí)行存儲過程個,并返回對應(yīng)的返回參數(shù),我們可以在程序里面利用代碼獲取這些返回參數(shù)的數(shù)值,從而用作其他用途。
因此,這種操作,如要是獲取返回性參數(shù)的情況,如下所示是判斷記錄是否存在,以及獲取客戶最大年齡的兩個存儲過程。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢查表中是否存在符合條件的記錄
------------------------------------
CREATE PROCEDURE dbo.T_Customer_ExistByID
(
@Exist int output ,
@ID varchar(50)
)
AS
Select @Exist = Case When Exists (Select 1 From dbo.T_Customer Where ID=@ID) Then 1 Else 0 End
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:獲取客戶最大年齡
------------------------------------
CREATE PROCEDURE dbo.T_Customer_MaxAge
( @MaxAge int output )
AS
Select @MaxAge=Case When Max(Age) is NULL Then 0 Else Max(Age) End From dbo.T_Customer
go
3)提供查詢處理,并返回實體對象
這小節(jié)后面介紹的內(nèi)容,都是存儲過程的返回值,這些或者是一條記錄,或者是多條記錄的查詢結(jié)果,這個在SQLServer里面很容易實現(xiàn),而在Oracle里面需要通過游標進行處理。
下面存儲過程腳本,是基于返回單條記錄的存儲過程。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢索表中的數(shù)據(jù)
------------------------------------
CREATE PROCEDURE dbo.T_Customer_SelectByID
(
@ID varchar(50)
)
AS
Select * from dbo.T_Customer Where ID= @ID
go
4)提供查詢處理,并返回多條記錄集合;包括實體列表集合或DataTable集合對象
對于返回多條集合的對象,在存儲過程里面體現(xiàn)都一樣的,我們可能在C#處理的時候,把它轉(zhuǎn)換為不同的對象即可,返回多個集合,在SQLServer里面,它們的存儲過程代碼如下所示。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:檢索表中所有的數(shù)據(jù)
------------------------------------
CREATE PROCEDURE dbo.T_Customer_SelectAll
AS
Select * from dbo.T_Customer
go
2、Oracle存儲過程的編寫
對應(yīng)客戶表T_Customer,Oracle的創(chuàng)建腳本如下所示。
CREATE TABLE T_CUSTOMER (
ID VARCHAR2(100),
NAME VARCHAR2(50) NOT NULL ,
AGE INTEGER NOT NULL,
CREATOR VARCHAR2(50) NULL,
CREATETIME DATE DEFAULT SYSDATE,
);
ALTER TABLE T_CUSTOMER ADD CONSTRAINT PK_T_CUSTOMER PRIMARY KEY (ID);
對應(yīng)SQLServer的存儲過程,Oracle的存儲過程也提供了對應(yīng)的版本,下面是幾種情況下的Oracle存儲過程的編寫。
1)提供執(zhí)行處理,可對執(zhí)行結(jié)果進行反饋
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:插入數(shù)據(jù)到表中
------------------------------------
Create Or Replace Procedure T_Customer_Insert
(
p_ID IN T_CUSTOMER.ID%TYPE,
p_Name IN T_CUSTOMER.NAME%TYPE,
p_Age IN T_CUSTOMER.AGE%TYPE
)
AS
Begin
Insert into T_CUSTOMER( ID,NAME,AGE ) Values( p_ID,p_Name,p_Age ) ;
Commit;
Exception
When Others Then
Rollback;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,修改表中的數(shù)據(jù)
------------------------------------
Create Or Replace Procedure T_Customer_UpdateByID
(
p_ID IN T_CUSTOMER.ID%TYPE,
p_Name IN T_CUSTOMER.NAME%TYPE,
p_Age IN T_CUSTOMER.AGE%TYPE
)
AS
Begin
Update T_CUSTOMER Set NAME=p_Name,AGE=p_Age Where ID= p_ID ;
Commit;
Exception
When Others Then
Rollback;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,刪除表的記錄
------------------------------------
Create Or Replace Procedure T_Customer_DeleteByID
(
p_ID IN T_CUSTOMER.ID%TYPE
)
AS
Begin
Delete From T_CUSTOMER where ID=p_ID ;
Commit;
Exception
When Others Then
Rollback;
End;
/
其中上面的代碼涉及幾個地方,T_CUSTOMER.ID%TYPE是表示根據(jù)字段動態(tài)決定參數(shù)的類型,避免應(yīng)硬編碼或者反復(fù)修改參數(shù)類型。
Oracle的參數(shù)一般使用p_的前綴開始,方便區(qū)分。
2)提供執(zhí)行處理,獲得一個或者多個返回性參數(shù),并可對執(zhí)行結(jié)果進行反饋。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢查表中是否存在符合條件的記錄
------------------------------------
Create Or Replace Procedure T_Customer_ExistByID
(
p_Exist OUT Number ,
p_ID IN T_CUSTOMER.ID%TYPE
)
AS
Begin
--V9.i以下使用的語句
Select Case When (Count(1)>0) Then 1 Else 0 End Into p_Exist From T_CUSTOMER Where ID=p_ID ;
--也可以使用的語句
-- Select Decode(Count(1),0,0,1) Into p_Exist From T_CUSTOMER Where ID=p_ID ;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:獲取表用來標識字段的最大ID值,在標識ID非自增字段時可用于數(shù)據(jù)插入時調(diào)用
------------------------------------
Create Or Replace Procedure T_Customer_MaxAge
(
p_MaxAge OUT Number
)
AS
Begin
Select Decode(Max(Age) ,NULL,0,Max(Age)) Into p_MaxAge From T_CUSTOMER;
End;
/
上面的代碼,都有一個輸出的參數(shù),雖然他們執(zhí)行沒有影響記錄函數(shù),但是這個主要是通過輸出參數(shù)的值進行處理了。
3)提供查詢處理,并返回實體對象
提供查詢處理,不管返回一條記錄,還是多條記錄,在Oracle里面,一般都是通過游標進行處理的,因此我們需要先定義一個游標類型,供我們返回記錄使用的。
下面定義一個游標的包代碼如下。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:創(chuàng)建一個包,含有一個游標類型:(一個數(shù)據(jù)庫中只需聲明一次)
------------------------------------
CREATE OR REPLACE PACKAGE MyCURSOR
AS
TYPE cur_OUT IS REF CURSOR;
End;
/
然后我們就可以在各個返回記錄的存儲過程里面使用這個游標類型了。
例如在下面的存儲過程里面,返回一條指定的數(shù)據(jù)記錄,那么輸出參數(shù)里面需要有一個游標的定義參數(shù),但是我們在C#里面使用數(shù)據(jù)訪問框架來處理數(shù)據(jù)的時候,可以忽略他它的存在,就只需要輸入p_ID參數(shù)就可以了。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢索表中的數(shù)據(jù)
------------------------------------
Create Or Replace Procedure T_Customer_SelectByID
(
cur_OUT OUT MyCURSOR.cur_OUT ,
p_ID IN T_CUSTOMER.ID%TYPE
)
AS
Begin
OPEN cur_OUT FOR Select * from T_CUSTOMER Where ID = p_ID ;
End;
/
4)提供查詢處理,并返回多條記錄集合;包括實體列表集合或DataTable集合對象
和上面返回單條記錄一樣,需要返回多條記錄的存儲過程,也需要使用一個游標的輸出參數(shù)來獲取返回的記錄,并可以對游標進行處理。
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:檢索表中所有的數(shù)據(jù)
------------------------------------
Create Or Replace Procedure T_Customer_SelectAll
( cur_OUT OUT MyCURSOR.cur_OUT )
AS
Begin
OPEN cur_OUT FOR Select * from T_CUSTOMER;
End;
/
最后,我們看看SQLServer和Oracle數(shù)據(jù)庫的腳本完整情況。
SQLServer存儲過程代碼:
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:插入數(shù)據(jù)到表中
------------------------------------
CREATE PROCEDURE dbo.T_Customer_Insert
(
@ID varchar(50),
@Name varchar(50) ,
@Age int
)
AS
begin tran
Insert into dbo.T_Customer( ID,Name,Age ) Values( @ID,@Name,@Age )
if @@error!=0
begin
rollback
end
else
begin
commit
end
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,修改表中的數(shù)據(jù)
------------------------------------
CREATE PROCEDURE dbo.T_Customer_UpdateByID
(
@ID varchar(50),
@Name varchar(50) ,
@Age int
)
AS
begin tran
Update dbo.T_Customer Set Name=@Name,Age=@Age Where ID= @ID
if @@error!=0
begin
rollback
end
else
begin
commit
end
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:檢索表中所有的數(shù)據(jù)
------------------------------------
CREATE PROCEDURE dbo.T_Customer_SelectAll
AS
Select * from dbo.T_Customer
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢索表中的數(shù)據(jù)
------------------------------------
CREATE PROCEDURE dbo.T_Customer_SelectByID
(
@ID varchar(50)
)
AS
Select * from dbo.T_Customer Where ID= @ID
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢查表中是否存在符合條件的記錄
------------------------------------
CREATE PROCEDURE dbo.T_Customer_ExistByID
(
@Exist int output ,
@ID varchar(50)
)
AS
Select @Exist = Case When Exists (Select 1 From dbo.T_Customer Where ID=@ID) Then 1 Else 0 End
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,刪除表的記錄
------------------------------------
CREATE PROCEDURE dbo.T_Customer_DeleteByID
(
@ID varchar(50)
)
AS
begin tran
Delete From dbo.T_Customer where ID=@ID
if @@error!=0
begin
rollback
end
else
begin
commit
end
go
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:獲取客戶最大年齡
------------------------------------
CREATE PROCEDURE dbo.T_Customer_MaxAge
( @MaxAge int output )
AS
Select @MaxAge=Case When Max(Age) is NULL Then 0 Else Max(Age) End From dbo.T_Customer
go
Oracle存儲過程代碼:
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:插入數(shù)據(jù)到表中
------------------------------------
Create Or Replace Procedure T_Customer_Insert
(
p_ID IN T_CUSTOMER.ID%TYPE,
p_Name IN T_CUSTOMER.NAME%TYPE,
p_Age IN T_CUSTOMER.AGE%TYPE
)
AS
Begin
Insert into T_CUSTOMER( ID,NAME,AGE ) Values( p_ID,p_Name,p_Age ) ;
Commit;
Exception
When Others Then
Rollback;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,修改表中的數(shù)據(jù)
------------------------------------
Create Or Replace Procedure T_Customer_UpdateByID
(
p_ID IN T_CUSTOMER.ID%TYPE,
p_Name IN T_CUSTOMER.NAME%TYPE,
p_Age IN T_CUSTOMER.AGE%TYPE
)
AS
Begin
Update T_CUSTOMER Set NAME=p_Name,AGE=p_Age Where ID= p_ID ;
Commit;
Exception
When Others Then
Rollback;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:創(chuàng)建一個包,含有一個游標類型:(一個數(shù)據(jù)庫中只需聲明一次)
------------------------------------
CREATE OR REPLACE PACKAGE MyCURSOR
AS
TYPE cur_OUT IS REF CURSOR;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:檢索表中所有的數(shù)據(jù)
------------------------------------
Create Or Replace Procedure T_Customer_SelectAll
( cur_OUT OUT MyCURSOR.cur_OUT )
AS
Begin
OPEN cur_OUT FOR Select * from T_CUSTOMER;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢索表中的數(shù)據(jù)
------------------------------------
Create Or Replace Procedure T_Customer_SelectByID
(
cur_OUT OUT MyCURSOR.cur_OUT ,
p_ID IN T_CUSTOMER.ID%TYPE
)
AS
Begin
OPEN cur_OUT FOR Select * from T_CUSTOMER Where ID = p_ID ;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,檢查表中是否存在符合條件的記錄
------------------------------------
Create Or Replace Procedure T_Customer_ExistByID
(
p_Exist OUT Number ,
p_ID IN T_CUSTOMER.ID%TYPE
)
AS
Begin
--V9.i以下使用的語句
Select Case When (Count(1)>0) Then 1 Else 0 End Into p_Exist From T_CUSTOMER Where ID=p_ID ;
--V8.i及以下使用的語句
-- Select Decode(Count(1),0,0,1) Into p_Exist From T_CUSTOMER Where ID=p_ID ;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:以字段ID為關(guān)鍵字,刪除表的記錄
------------------------------------
Create Or Replace Procedure T_Customer_DeleteByID
(
p_ID IN T_CUSTOMER.ID%TYPE
)
AS
Begin
Delete From T_CUSTOMER where ID=p_ID ;
Commit;
Exception
When Others Then
Rollback;
End;
/
------------------------------------
--作者:伍華聰 http://wuhuacong.cnblogs.com
--創(chuàng)建時間:2014年11月27日
--功能描述:獲取表用來標識字段的最大ID值,在標識ID非自增字段時可用于數(shù)據(jù)插入時調(diào)用
------------------------------------
Create Or Replace Procedure T_Customer_MaxAge
(
p_MaxAge OUT Number
)
AS
Begin
Select Decode(Max(Age) ,NULL,0,Max(Age)) Into p_MaxAge From T_CUSTOMER;
End;
/
以上就是存儲過程編寫過程中的處理和對比,下一篇將繼續(xù)介紹這個主體,并針對性的介紹如何在C#底層數(shù)據(jù)訪問里面,對這些存儲過程的使用。