- 在线时间
- 0 小时
- 最后登录
- 2007-9-23
- 注册时间
- 2004-9-10
- 听众数
- 3
- 收听数
- 0
- 能力
- 0 分
- 体力
- 9975 点
- 威望
- 7 点
- 阅读权限
- 150
- 积分
- 4048
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 1893
- 主题
- 823
- 精华
- 2
- 分享
- 0
- 好友
- 0

我的地盘我做主
该用户从未签到
 |
长期以来,我一直用的是 MS SQL Server / Access 数据库,通过.NET 访问MS自家的东西几乎没碰到过什么麻烦。最近项目中要用 Oracle 作为数据库,学习研究了一些 .NET 访问Oracle 的东西,发现问题倒真的不少。
; W& u- U. h! Y9 |& J3 \< >
7 O4 N* t: q9 r& }* q) Z" ]8 L% R2 p( _: |, N" ~
flash/swflash.cab#version=5,0,0,0 height=280 width=320 classid=clsid 27CDB6E-AE6D-11cf-96B8-444553540000>200309/guangli_320.swf">200309/guangli_320.swf"> 200309/guangli_320.swf" width=320 height=280 type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">1。System.Data.OracleClient 和 System.Data.OleDb 命名空间</P>
! ^1 k# H' Z6 z$ c6 k< > 虽然通过这两个命名空间的类都可以访问 Oracle 数据库,但和 SQL Server 类似的(System.Data.SqlClient 命名空间的类效率要比 System.Data.OleDb 命名空间中的类高一些),System.Data.OracleClient 命名空间中的类要比 System.Data.OleDb 命名空间的类效率高一些(这一点我没有亲自验证,但大多数地方都会这么说,而且既然专门为 Oracle 作的东西理论上也应该专门作过针对性的优化)。</P>
: E+ W1 d( Z, `< > 当然还有另一点就是从针对性上说,System.Data.OracleClient 要更好一些:</P>
& H/ k- D" [# |< > 比如数据类型,System.Data.OleDb.OleDbType 枚举中所列的就没有 System.Data.OracleClient.OracleType 枚举中的那些有针对性;另外,Oracle 的Number 类型如果数字巨大,超出 .NET 数据类型范围的情况中,就必须使用System.Data.OracleClient 中的专门类 -- OracleNumber 类型。</P>" U( h( s6 L* G, ~+ h8 p# H
< > 好了,不再赘述这两个的比较,下面主要讨论System.Data.OracleClient 命名空间中的类型,即 ADO.NET for Oracle Data Provider (数据提供程序)。</P>, n9 |8 Z1 O6 ?$ C, m9 c5 H) H; u
< >2。数据库连接:</P>: a: t' N! Q5 O8 k; r" E& q+ Q
< > 无论是 System.Data.OleDb 还是 System.Data.OracleClient 访问 Oracle 都需要在 .NET 运行的机器(ASP.NET 中就是 Web 服务器)安装 Oracle 客户端组件。(这一点是和 MS 的两种数据库不同的,MS 的东西安装 MDAC: Microsoft Data Access Component 2.6 以上版本后,就无须再安装 SQL Server 客户端或者 Office 软件,就能访问。)</P>
- W/ s% C5 {9 A0 a( q< >System Requirements:</P> U7 A( i! i% `! y
< > (1)如用 System.Data.OracleClient 访问 Oracle,客户端组件版本应在 Oracle 8i Client Release 3 (8.1.7)以上版本。MS 只确保访问 Oracle 8.1.6、Oracle 8.1.7、Oracle 9i 服务器时的情况。MDAC 2.6 以上。</P>2 y# a, K9 M; H+ e9 e% T, D. }
< > (2)如用 System.Data.OleDb 访问 Oracle,客户端组件版本 7.3.3.4.0 以上或 8.1.7.4.1 以上。MDAC 2.6 以上。</P>% [1 i* \* V' t* {- u" g
< > 如服务器为 Oracle8i 以上,客户端组件版本应为 8.0.4.1.1c。</P>
8 z. ~) B1 N. I2 v$ U2 w4 c< > 在 .NET 运行的机器中,安装 Oracle 客户端,然后打开 Net Manager (Oracle 9i) / Easy Config (Oracle 8i) 按你以前的经验设置本地服务的映射(这里的服务名将用于数据库连接串)。</P>
1 Z' o" D' m0 h< > System.Data.OracleClient 中访问 Oracle 数据库的连接串是:</P>4 ^* {3 J6 l; ` s
< >User ID=用户名; Password=密码; Data Source=服务名</P>
: P4 B# l. P/ I, x8 n; S< > (上述为一般的连接串,详细的连接串项目可以在 System.Data.OracleClient.OracleConnection.ConnectionString 属性的文档中找到。)</P>1 q0 w3 {# r* v( a( n9 a. `! ]
< > System.Data.OleDb 中的访问 Oracle 数据库的连接串是:</P>
! o% `- w u$ ~# G; _1 w" O& Z5 p$ D< > rovider=MSDAORA.1; User ID=用户名; Password=密码; Data Source=服务名</P>
" B( B+ w3 W6 J% C) s< >3。Oracle 中的数据类型:</P>0 ]! K! r; p% u N
< > Oracle 的数据类型和 SQL Server 相比,要“奇怪”一些:SQL Server 的大多数据类型很容易找到 .NET 中比较接近的类型,Oracle 中的类型就离 .NET 类型远了许多,毕竟 Oracle 是和 Java 亲近的数据库。</P>9 e- l& [& J! J
number: 数字类型,一般是 Number(M,N),M是有效数字,N是小数点后的位数(默认0),这个是按十进制说的。
& r$ O5 U% z" A; dnvarchar2: 可变长字符型(Unicode),这个比较像 SQL Server 的 nvarchar(但不知 Oracle 为什么加了个“2”)。(去掉“n”为非 Unicode 的,下同。)
/ ?. p' {% w* U4 hnchar: 定长字符型(Unicode)。
5 p; K! ^7 y Jnclob: “写作文”的字段,存储大量字符(Unicode)时用。
: y5 C: M% b, @- U4 l5 N) z+ Hdate: 日期类型,比较接近 SQL Server 的 datetime。
8 S3 ?" v* e1 @% S4 i s< > Oracle 中字段不能是 bit 或者 bool 之类的类型,一般是 number(1) 代替的。</P>8 o- ?( l. N7 g/ i1 z
< > 和 SQL Server 一样在 SQL 命令中,字符类型需要用单引号(')隔开,两个单引号('')是单引号的字符转义(比如: I'm fat. 写入一个 SQL 命令是: UPDATE ... SET ...='I''m fat.' ...)。</P>
/ H4 l0 X. h$ _1 Q9 K6 n( t% N5 t' ^< > 比较特殊的是日期类型:比如要写入 2004-7-20 15:20:07 这个时刻需要如下写:</P>* s/ W+ b" G* {+ U E4 L3 D Z7 @
< >UPDATE ... SET ... = TIMESTAMP '2004-7-20 15:20:07' ...</P>
B$ m; Y- c) N* }2 L5 {- ]< >注意这里使用了 TIMESTAMP 关键字,并使用单引号隔开;另外请注意日期格式,上面的格式是可识别的,Oracle 识别的格式没有 SQL Server 那般多。这是和 SQL Server 不同的地方。</P>' Z7 K/ S& v; `. X/ S; M& E
< >顺便提一句:Access 中的日期类型是用井号(#)隔开的,UPDATE ... SET ... = #2004-7-20 15:20:07# ...</P>
h$ q- X2 ^5 E* U3 |< >4。访问 Oracle 过程/函数(1)</P>7 Q/ n8 U. \5 u0 G$ e
< > SQL Server 作程序时经常使用存储过程,Oracle 里也可以使用过程,还可以使用函数。Oracle 的过程似乎是不能有返回值的,有返回值的就是函数了(这点有些像 BASIC,函数/过程区分的很细致。SQL Server 存储过程是可以有返回值的)。</P>% ~3 N/ o2 P. h" w
< >.NET 访问 Oracle 过程/函数的方法很类似于 SQL Server,例如:</P>9 O( b6 H1 f8 N, |6 U
< >OracleParameter[] parameters = {% n5 I4 Y& Q" B
new OracleParameter("ReturnValue", OracleType.Int32, 0, ParameterDirection.ReturnValue, true, 0, 0, "",0 `# O7 D7 c- | N1 \- ]
DataRowVersion.Default, Convert.DBNull )8 G) ]2 Z" e! ~ A+ P. \
new OracleParameter("参数1", OracleType.NVarChar, 10),
j, R1 F/ E1 q6 _7 t" A ] new OracleParameter("参数2", OracleType.DateTime),
7 h1 W+ M9 ?0 w+ G: W! s new OracleParameter("参数3", OracleType.Number, 1)% ]: [" Q" `: p, x4 u8 J
};
& v7 a. v5 a" P, i6 S
" b+ {; p7 G7 ~7 p5 L& Q {$ M$ }0 W& tparameters[1].Value = "test";
# m; A. Q! Z( L/ ]3 M! [4 l/ T4 y0 Eparameters[2].Value = DateTime.Now;- O1 d w3 h! N; n/ ?1 l D
parameters[3].Value = 1; // 也可以是 new OracleNumber(1);</P>
$ z7 i+ H; t) c$ L6 W9 }<P>OracleConnection connection = new OracleConnection( ConnectionString );
E' M9 \% M8 JOracleCommand command = new OracleCommand("函数/程名", connection);, \5 l1 X9 N* g2 E: c+ F
command.CommandType = CommandType.StoredProcedure;& G4 o4 ]& l* Q! u ^3 j
9 ]5 c: C4 l3 J5 Fforeach(OracleParameter parameter in parameters)
2 ]# J1 e2 U: t command.Parameters.Add( parameter );
$ ~+ V+ H8 L3 q+ i+ v5 J% E0 ?; p: R0 ]0 ^! A) z. Z
connection.Open();9 C( b' ~$ x. z
command.ExecuteNonQuery();
. @ V4 p# ]$ u$ n7 p0 \int returnValue = parameters[0].Value; //接收函数返回值
" v1 |# {. M" Zconnection.Close();</P>
& V8 P: M, f0 W" S' ?; l<P> Parameter 的 DbType 设定请参见 System.Data.OracleClient.OracleType 枚举的文档,比如:Oracle 数据库中 Number 类型的参数的值可以用 .NET decimal 或 System.Data.OracleClient.OracleNumber 类型指定; Integer 类型的参数的值可以用 .NET int 或 OracleNumber 类型指定。等等。</P>% Q# g2 C" Y8 B% ]" b. Z6 G: T3 S
<P> 上面例子中已经看到函数返回值是用名为“ReturnValue”的参数指定的,该参数为 ParameterDirection.ReturnValue 的参数。</P>
: `: i2 X y! y- X2 y* ?) k1 s<P>5。访问 Oracle 过程/函数 (2)</P>
$ ^5 d9 y6 |& Y1 g<P> 不返回记录集(没有 SELECT 输出)的过程/函数,调用起来和 SQL Server 较为类似。但如果想通过过程/函数返回记录集,在 Oracle 中就比较麻烦一些了。</P>
% u! d8 i6 e! p A g1 x# e<P>在 SQL Server 中,如下的存储过程:</P>0 I- O1 P2 `' D d
<P>CREATE PROCEDURE GetCategoryBooks
% W+ |. O) e X! |( C(
/ V) W+ ]2 J2 g! L- j4 q9 H# R @CategoryID int7 y# x. ?# X9 Z
)
1 x/ a# |, W; F L3 yAS
/ C! ]+ S; z# l4 f& h* ~SELECT * FROM Books, U, W: E" e$ d$ J) {; d
WHERE CategoryID = @CategoryID
# x: E2 j1 P! x S, yGO</P>$ s8 i9 R- z5 U0 y5 v0 c
<P> 在 Oracle 中,请按以下步骤操作:</P>, q1 A. u9 j6 v4 F# s1 C
<P>(1)创建一个包,含有一个游标类型:(一个数据库中只需作一次)</P>
' Z; Y1 j/ N9 P- n9 L9 F<P>CREATE OR REPLACE PACKAGE Test
9 W, H7 h2 Q. f# l! o* [ AS
1 L0 ^+ E2 [+ N- P# R" q7 R4 v TYPE Test_CURSOR IS REF CURSOR;
. o( b" y2 l z- O. MEND Test;</P>" s( h/ E6 [$ I3 q# L/ H9 a
<P>(2)过程:</P>2 n4 C! z! h$ ?: ~1 P9 S3 x3 j
<P>CREATE OR REPLACE PROCEDURE GetCategoryBooks; d$ z( O* w" _' v7 @
(
# P! o5 G! p' n( ?1 N( O0 f p_CURSOR out Test.Test_CURSOR, -- 这里是上面包中的类型,输出参数
9 p6 [; _6 n$ K8 r p_CatogoryID INTEGER
1 u# `( B. I C9 f)
* {' o0 |3 g2 @' C% oAS( ]7 _0 A7 p3 ^$ o" u! j
BEGIN7 J$ A; [. O+ i; i0 n8 ]
OPEN p_CURSOR FOR3 v7 U. O6 M8 L
SELECT * FROM Books
]% a3 x* Z- O& O) K+ Q WHERE CategoryID=p_CatogoryID;
) A+ a& {7 M, H0 X( dEND GetCategoryBooks;</P>
' M, H6 F7 I" l6 m* i6 V# H<P>(3).NET 程序中:</P>8 V ?1 A& e8 i1 b6 `5 @+ W
<P>OracleParameters parameters = {
% p: k9 J; [7 d new OracleParameter("p_CURSOR", OracleType.CURSOR, 2000, ParameterDirection.Output, true, 0, 0, "",
! z$ ?9 ~4 L3 t DataRowVersion.Default, Convert.DBNull),& T# v7 `) m$ d* w3 s
new OracleParameter("p_CatogoryID", OracleType.Int32)4 [4 M% I/ N2 `! w0 p w! T
};
) f3 F9 H9 Q4 Y/ O5 \! i/ m( {7 ]
( p, w7 q$ b# F7 N& \parameters[1].Value = 22;8 U$ `# S2 j R- o8 E0 \% j
' B; i9 x3 A0 M- JOracleConnection connection = new OracleConnection( ConnectionString );
# l) t* B* R3 [. DOracleCommand command = new OracleCommand("GetCategoryBooks", connection);
4 r5 l% Z+ i8 tcommand.CommandType = CommandType.StoredProcedure;
3 J1 A0 W3 m. ?
( [8 Q) z# I) c6 a ]foreach(OracleParameter parameter in parameters)
) v9 ?8 S. I* B# B4 C command.Parameters.Add( parameter );
0 f7 H& l( D8 |% P+ `' a
: Q$ X8 S5 K& j3 J; ^- N* ?6 P" xconnection.Open();
' d w( i/ Z6 f( zOracleDataReader dr = command.ExecuteReader();
4 C' B) H$ Y. _( _0 F4 F4 ~( c6 B/ F! k
while(dr.Read())& b6 ]7 r8 ^1 ?5 Q$ E% _8 X/ E
{* v3 [" o. @5 g5 w. t; K7 o5 `
// 你的具体操作。这个就不需要我教吧?# ?; Z' c7 X8 g: T
}
2 D: ~( K# Z5 ^3 R: k' T5 i+ Yconnection.Close();</P>" j& Y! O$ G" Y+ ~) f
<P> 另外有一点需要指出的是,如果使用 DataReader 取得了一个记录集,那么在 DataReader 关闭之前,程序无法访问输出参数和返回值的数据。</P>1 n9 R, X1 z9 ?, L
<P> 好了,先这些,总之 .NET 访问 Oracle 还是有很多地方和 SQL Server 不同的,慢慢学习了。</P>
- F ~/ a+ M% w9 c<P> |
zan
|