- 在线时间
- 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 的东西,发现问题倒真的不少。
# v; m! o9 M9 U; |1 W' }< >) D" K' a' F! F: x' X/ Z0 `
: p4 ~' @7 s, [: r
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>2 U$ s9 I" f+ [. H2 m I
< > 虽然通过这两个命名空间的类都可以访问 Oracle 数据库,但和 SQL Server 类似的(System.Data.SqlClient 命名空间的类效率要比 System.Data.OleDb 命名空间中的类高一些),System.Data.OracleClient 命名空间中的类要比 System.Data.OleDb 命名空间的类效率高一些(这一点我没有亲自验证,但大多数地方都会这么说,而且既然专门为 Oracle 作的东西理论上也应该专门作过针对性的优化)。</P># w# Z+ _6 m! ~: ?
< > 当然还有另一点就是从针对性上说,System.Data.OracleClient 要更好一些:</P>
n. d# }% p" H6 u, w) f< > 比如数据类型,System.Data.OleDb.OleDbType 枚举中所列的就没有 System.Data.OracleClient.OracleType 枚举中的那些有针对性;另外,Oracle 的Number 类型如果数字巨大,超出 .NET 数据类型范围的情况中,就必须使用System.Data.OracleClient 中的专门类 -- OracleNumber 类型。</P>/ B2 b8 n G9 U% a, G
< > 好了,不再赘述这两个的比较,下面主要讨论System.Data.OracleClient 命名空间中的类型,即 ADO.NET for Oracle Data Provider (数据提供程序)。</P>
4 B7 \$ e+ Y0 }6 \) f3 Z< >2。数据库连接:</P>* U7 r. l% l8 R+ ?$ A" T
< > 无论是 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>
3 g* F: `( y9 G. f- P$ D< >System Requirements:</P>
1 G K* d9 V- B" _. P! T0 J+ p< > (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> y4 s, Y! X% W7 s, u2 f
< > (2)如用 System.Data.OleDb 访问 Oracle,客户端组件版本 7.3.3.4.0 以上或 8.1.7.4.1 以上。MDAC 2.6 以上。</P>
1 d1 l) ?4 B# h. I< > 如服务器为 Oracle8i 以上,客户端组件版本应为 8.0.4.1.1c。</P>
9 i( p7 V* a; D! i< > 在 .NET 运行的机器中,安装 Oracle 客户端,然后打开 Net Manager (Oracle 9i) / Easy Config (Oracle 8i) 按你以前的经验设置本地服务的映射(这里的服务名将用于数据库连接串)。</P>
# S9 \0 n9 T; b9 {. t, g< > System.Data.OracleClient 中访问 Oracle 数据库的连接串是:</P>
+ @4 Q2 O5 |9 L0 A% M! s/ r< >User ID=用户名; Password=密码; Data Source=服务名</P>
5 I# f3 k+ t5 n, D& k7 ^" d2 M- f< > (上述为一般的连接串,详细的连接串项目可以在 System.Data.OracleClient.OracleConnection.ConnectionString 属性的文档中找到。)</P>
5 O% N- ?# U# s/ o8 K/ C< > System.Data.OleDb 中的访问 Oracle 数据库的连接串是:</P>' ?/ t+ W$ V8 {- N! l8 Y0 g
< > rovider=MSDAORA.1; User ID=用户名; Password=密码; Data Source=服务名</P>* r5 [2 Y! R2 o4 d. I
< >3。Oracle 中的数据类型:</P>
- ^, w: {5 R* f( e1 _< > Oracle 的数据类型和 SQL Server 相比,要“奇怪”一些:SQL Server 的大多数据类型很容易找到 .NET 中比较接近的类型,Oracle 中的类型就离 .NET 类型远了许多,毕竟 Oracle 是和 Java 亲近的数据库。</P>
3 Q: m# N6 y" \: g; z9 ynumber: 数字类型,一般是 Number(M,N),M是有效数字,N是小数点后的位数(默认0),这个是按十进制说的。
3 G, ~+ [0 y; u% jnvarchar2: 可变长字符型(Unicode),这个比较像 SQL Server 的 nvarchar(但不知 Oracle 为什么加了个“2”)。(去掉“n”为非 Unicode 的,下同。) * n& Q- r7 E2 X) n
nchar: 定长字符型(Unicode)。 & c# d' P# g( l
nclob: “写作文”的字段,存储大量字符(Unicode)时用。 7 _% x3 r1 j/ }8 I5 T& N
date: 日期类型,比较接近 SQL Server 的 datetime。 J; @8 Z* ^+ F
< > Oracle 中字段不能是 bit 或者 bool 之类的类型,一般是 number(1) 代替的。</P>
/ K) E2 W$ F& r+ B< > 和 SQL Server 一样在 SQL 命令中,字符类型需要用单引号(')隔开,两个单引号('')是单引号的字符转义(比如: I'm fat. 写入一个 SQL 命令是: UPDATE ... SET ...='I''m fat.' ...)。</P>
! |# V7 M, R& T: ]" y9 B$ Y< > 比较特殊的是日期类型:比如要写入 2004-7-20 15:20:07 这个时刻需要如下写:</P>
( o1 M1 K2 {; d; W< >UPDATE ... SET ... = TIMESTAMP '2004-7-20 15:20:07' ...</P>
2 X( ?: d: y. X7 F# m+ \< >注意这里使用了 TIMESTAMP 关键字,并使用单引号隔开;另外请注意日期格式,上面的格式是可识别的,Oracle 识别的格式没有 SQL Server 那般多。这是和 SQL Server 不同的地方。</P>
5 ^9 e/ k5 z) `- d8 P! Y< >顺便提一句:Access 中的日期类型是用井号(#)隔开的,UPDATE ... SET ... = #2004-7-20 15:20:07# ...</P>
/ e- N* N8 w& ^$ s# t% u< >4。访问 Oracle 过程/函数(1)</P>' S1 ?1 v. @% n4 C' v
< > SQL Server 作程序时经常使用存储过程,Oracle 里也可以使用过程,还可以使用函数。Oracle 的过程似乎是不能有返回值的,有返回值的就是函数了(这点有些像 BASIC,函数/过程区分的很细致。SQL Server 存储过程是可以有返回值的)。</P>; O! G1 o% u8 ~3 d! g/ l3 ^
< >.NET 访问 Oracle 过程/函数的方法很类似于 SQL Server,例如:</P>
8 f$ z" o! m5 c% c< >OracleParameter[] parameters = {$ z! i5 B" K2 Z. D5 t6 a
new OracleParameter("ReturnValue", OracleType.Int32, 0, ParameterDirection.ReturnValue, true, 0, 0, "",
3 r C3 z9 X, _/ K8 N6 @ DataRowVersion.Default, Convert.DBNull )' G8 y# ~& K) L, _0 z9 v. J
new OracleParameter("参数1", OracleType.NVarChar, 10),
# [2 A, z. }4 o/ U2 _ new OracleParameter("参数2", OracleType.DateTime),
' K1 L1 S" a i new OracleParameter("参数3", OracleType.Number, 1)- c) f9 r; p7 @# U8 s
};' m6 y' O5 L/ G3 D8 F( V. p
% R9 ^% Q$ t X5 h! _/ A
parameters[1].Value = "test";: A& |8 ]) i* t8 l% z" I
parameters[2].Value = DateTime.Now; Q- C! q: ]/ b
parameters[3].Value = 1; // 也可以是 new OracleNumber(1);</P>
/ V }/ w" n; r0 m. A6 ^$ h<P>OracleConnection connection = new OracleConnection( ConnectionString );8 F6 z: w. `5 @
OracleCommand command = new OracleCommand("函数/程名", connection);4 I6 y4 M, ~3 {5 E2 s, t7 N
command.CommandType = CommandType.StoredProcedure;) q- w6 T: o2 T! S! e; Q
: p+ e! l: f0 b" h
foreach(OracleParameter parameter in parameters)
: f1 e+ p/ {$ c; u2 R command.Parameters.Add( parameter );( y q: ^) ^* l% t8 |
7 n" p. Y% x7 P) }1 T" Q1 N( j
connection.Open();8 G& J Z: |* R) X
command.ExecuteNonQuery();$ v6 b& M& Z6 Y/ G0 @
int returnValue = parameters[0].Value; //接收函数返回值9 ^9 I5 i. O( a2 |2 t
connection.Close();</P>4 P$ `% K$ G8 U. E s4 |
<P> Parameter 的 DbType 设定请参见 System.Data.OracleClient.OracleType 枚举的文档,比如:Oracle 数据库中 Number 类型的参数的值可以用 .NET decimal 或 System.Data.OracleClient.OracleNumber 类型指定; Integer 类型的参数的值可以用 .NET int 或 OracleNumber 类型指定。等等。</P>
8 c; A3 i, X1 E: ?<P> 上面例子中已经看到函数返回值是用名为“ReturnValue”的参数指定的,该参数为 ParameterDirection.ReturnValue 的参数。</P>
% O- d. o7 @, d<P>5。访问 Oracle 过程/函数 (2)</P>: G# a4 t6 ~. V/ q- W; C8 y; a
<P> 不返回记录集(没有 SELECT 输出)的过程/函数,调用起来和 SQL Server 较为类似。但如果想通过过程/函数返回记录集,在 Oracle 中就比较麻烦一些了。</P>1 r! O t* ~ c
<P>在 SQL Server 中,如下的存储过程:</P>9 ^& K4 S8 E' m3 W; O
<P>CREATE PROCEDURE GetCategoryBooks/ X9 T+ ~5 C4 u8 c; F
(' r0 C: c4 O/ x5 u
@CategoryID int
# y; F% H8 T9 r3 _* t)5 b$ A. W) F. R4 l5 S: P. V
AS
+ ?+ p% p o: V) A2 b- GSELECT * FROM Books7 j8 ~) H7 R% K) b2 W0 D
WHERE CategoryID = @CategoryID+ P' e# }) y/ {3 _
GO</P>
* A' O7 }( f; c4 [ G( c<P> 在 Oracle 中,请按以下步骤操作:</P>6 Q1 R8 F3 a% p& b5 k7 p3 X- h, b% Y$ N
<P>(1)创建一个包,含有一个游标类型:(一个数据库中只需作一次)</P>
+ }4 y& [: p: b% T<P>CREATE OR REPLACE PACKAGE Test0 q2 K2 B$ m4 |+ S9 H, H0 e9 K
AS
" E1 u; o% C) }) {. }( ] TYPE Test_CURSOR IS REF CURSOR;
0 \$ _' K* O2 eEND Test;</P>
. w7 p4 w) {- u& I" x/ a<P>(2)过程:</P>; a {5 U2 S# a# H( ?
<P>CREATE OR REPLACE PROCEDURE GetCategoryBooks
+ E5 D* {* B8 q" f, J(
* T- K& h; h; O% @# ?: } p_CURSOR out Test.Test_CURSOR, -- 这里是上面包中的类型,输出参数
6 r) f' Z9 d( q p_CatogoryID INTEGER
) e( Z( J; F/ p# F/ O)3 L1 _% P2 ?0 d1 U4 K- F" X
AS; t% _: e( L- t5 k; o( F/ J7 V
BEGIN" R( a$ \: L5 X. `4 B# _
OPEN p_CURSOR FOR
( y* c' _. s, t E" {/ e SELECT * FROM Books
/ j- y& n/ y' I$ A7 N WHERE CategoryID=p_CatogoryID;
5 W8 F S# Z5 Z, P$ CEND GetCategoryBooks;</P>2 B. m/ D4 Q9 ~) H8 |
<P>(3).NET 程序中:</P>
* E8 j8 a) i0 q' V7 v: O- T, f<P>OracleParameters parameters = {+ A$ p3 H1 X+ x1 E9 [
new OracleParameter("p_CURSOR", OracleType.CURSOR, 2000, ParameterDirection.Output, true, 0, 0, "",9 I/ Z" n- U$ U+ f& W
DataRowVersion.Default, Convert.DBNull),$ X$ d+ J) S/ z! `" Q
new OracleParameter("p_CatogoryID", OracleType.Int32)" k% ?1 ?; V+ _% p
};/ _! c8 `% @) ^6 Y- c. Z i y
: Y9 i- n8 t: g
parameters[1].Value = 22;
- x/ Q1 L* Q- L1 W; L* y; o+ A$ F- g& R8 z
OracleConnection connection = new OracleConnection( ConnectionString );9 r! l6 A u9 d k- b7 e- W
OracleCommand command = new OracleCommand("GetCategoryBooks", connection);5 G( B O. `, Y/ g, `
command.CommandType = CommandType.StoredProcedure;
5 `% h* |; i+ z( l/ c) j/ H
- Z2 Z" u2 L( u. z9 F, \foreach(OracleParameter parameter in parameters)# D* }9 M$ A4 ^0 W" M; N
command.Parameters.Add( parameter );9 F' s( x# v% S5 [6 h1 |- K& V( U
7 y+ W, `# T( v5 Xconnection.Open();- F. e4 |4 ^9 W, n6 }: ]- k0 c5 J
OracleDataReader dr = command.ExecuteReader();
6 l: w1 u; s4 N# X& P6 W2 f* W% c4 Y* \ F7 y( [! q: N
while(dr.Read())5 X9 `! S" t9 K6 J6 p( S' q% j
{' [' B9 z1 q) i/ _
// 你的具体操作。这个就不需要我教吧?2 M, Q2 c. k, v. ~. K2 G
}
* M5 u1 w" J& m! S) ]connection.Close();</P>% U# r T7 Q# v i
<P> 另外有一点需要指出的是,如果使用 DataReader 取得了一个记录集,那么在 DataReader 关闭之前,程序无法访问输出参数和返回值的数据。</P>
( q. u% @, x/ c7 \, S: T<P> 好了,先这些,总之 .NET 访问 Oracle 还是有很多地方和 SQL Server 不同的,慢慢学习了。</P>$ Q2 R7 v- h O# n! d
<P> |
zan
|