QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3438|回复: 1
打印 上一主题 下一主题

通过.NET访问 Oracle数据库

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-3 21:16 |只看该作者 |正序浏览
|招呼Ta 关注Ta
长期以来,我一直用的是 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=clsid27CDB6E-AE6D-11cf-96B8-444553540000&gt;200309/guangli_320.swf"&gt;200309/guangli_320.swf"&gt; 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"&gt;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
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
ilikenba 实名认证       

1万

主题

49

听众

2万

积分

  • TA的每日心情
    奋斗
    2024-6-23 05:14
  • 签到天数: 1043 天

    [LV.10]以坛为家III

    社区QQ达人 新人进步奖 优秀斑竹奖 发帖功臣

    群组万里江山

    群组sas讨论小组

    群组长盛证券理财有限公司

    群组C 语言讨论组

    群组Matlab讨论组

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-6-12 14:59 , Processed in 1.520120 second(s), 58 queries .

    回顶部