执行存储过程返回DataSet:
1.存储过程中 一定要有一个Output参数的游标,以便返回存储过程
--
建立存储过程的返回临时表
create
global
temporary
table
TMP_HIS_PPTN_JP
(
STCD
VARCHAR2
(
12
)
not
null
,
STNM
VARCHAR2
(
50
),
ADDVCD
VARCHAR2
(
6
),
RGNNM
VARCHAR2
(
50
),
HISAVG
NUMBER
(
13
,
3
),
ACCP
NUMBER
(
10
,
1
),
JP
NUMBER
(
10
,
2
)
)
on
commit
delete
rows;
--
[1]当事务完成后删除数据
alter
table
TMP_HIS_PPTN_JP
add
primary
key
(STCD);
--
建立存储过程
CREATE
OR
REPLACE
PROCEDURE
PROC_RAIN_JP(
V_STCDS
VARCHAR2
,
--
要求V_PTM1,V_PTM2不垮年 ,返回临时表TMP_HIS_PPTN_JP
V_PTM1
VARCHAR2
,
V_PTM2
VARCHAR2
,
V_CS OUT SYS_REFCURSOR
)
AS
--
定义变量......
BEGIN
--
数据的处理......
OPEN
V_CS
FOR
SELECT
*
FROM
TMP_HIS_PPTN_JP;
RETURN
;
END
;
2. 在C#中执行存储过程
IDbConnection con
=
this
.DBInterface.CreateConnection();
//
自已定义的数据访问接口
con.Open();
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
IDbTransaction trans
=
con.BeginTransaction();
cmd
=
con.CreateCommand();
cmd.Transaction
=
trans;
//
Set Transaction For Command
cmd.CommandType
=
System.Data.CommandType.StoredProcedure;
cmd.CommandText
=
"
PROC_RAIN_JP
"
;
System.Data.OracleClient.OracleParameter p;
p
=
new
System.Data.OracleClient.OracleParameter(
"
V_STCDS
"
, System.Data.OracleClient.OracleType.VarChar,
2000
);
cmd.Parameters.Add(p);
p.Direction
=
System.Data.ParameterDirection.Input;
p.Value
=
STC;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
p
=
new
System.Data.OracleClient.OracleParameter(
"
V_PTM1
"
, System.Data.OracleClient.OracleType.VarChar,
20
);
cmd.Parameters.Add(p);
p.Direction
=
System.Data.ParameterDirection.Input;
p.Value
=
this
.getParamValue(
"
SDATE
"
);
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
p
=
new
System.Data.OracleClient.OracleParameter(
"
V_PTM2
"
, System.Data.OracleClient.OracleType.VarChar,
20
);
cmd.Parameters.Add(p);
p.Direction
=
System.Data.ParameterDirection.Input;
p.Value
=
this
.getParamValue(
"
EDATE
"
);
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
输出的DataSet
p
=
new
System.Data.OracleClient.OracleParameter(
"
V_CS
"
, System.Data.OracleClient.OracleType.Cursor);
cmd.Parameters.Add(p);
p.Direction
=
System.Data.ParameterDirection.Output;
//
设置为Output
DataSet ds
=
new
DataSet();
IDbDataAdapter da
=
new
System.Data.OracleClient.OracleDataAdapter(cmd
as
System.Data.OracleClient.OracleCommand);
da.Fill(ds);
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
trans.Commit();
if
(con.State
!=
ConnectionState.Closed)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
try
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
con.Close();
}
catch
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
}
}
return
ds.Tables[
0
];
3.注意上边的C#代码我们是打开的一个事务,为会么呢:
如果我们没有用事务的话,在sqlplus中调试是没有任何问题的,但在是.net执行的时间就会报ORA-08103: object no longer exists 错误,原因就在存储过程中,临时表的创建选项由on commit delete rows[1]如果改为on commit preserve rows; 就不会有问题,但是在ASP.Net页中查询临时表数据时,每查一次都要多出一些重复记录原因肯定是Oracle的会话连接没有结束,导致每次执行存储过程都要先插入记录。Oracle会话为什么没有结束,肯定是ASP.NET服务程序在数据连接池中保持着与数据库的连接。但是为了性能我们也不能不用连接池。这样基于Oracle 会话的临时表是不能用了。
重新回到基于Oracle事务的临时表,也就是临时表的创建选项用on commit delete rows。然后,在ASP.Net应用程序中调用ODP自身的事务处理机制,问题得以解决!
注:
(1)理论上,不要在存储过程中执行Commit,即不要在存储过程中使用PL/SQL的事务处理, 否则ASP.NET页面也无法得到数据,因为commit 后,临时表中数据会自动清空。
(2)理论上,不用ODP的话,用OLEDB或微软提供的ORACLE事务处理机制应该也可以
[参考]