QQ登录

只需要一步,快速开始

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

通过.NET访问 Oracle数据库

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-3 21:16 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
长期以来,我一直用的是 MS SQL Server / Access 数据库,通过.NET 访问MS自家的东西几乎没碰到过什么麻烦。最近项目中要用 Oracle 作为数据库,学习研究了一些 .NET 访问Oracle 的东西,发现问题倒真的不少。
+ Z1 T" j9 E" w* G5 q* h<>( D9 r2 n" Y: m
  Q  }& U! A; V* V( k: W
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>% g7 B& |! D4 y+ K# ~+ i; I
<>  虽然通过这两个命名空间的类都可以访问 Oracle 数据库,但和 SQL Server 类似的(System.Data.SqlClient 命名空间的类效率要比 System.Data.OleDb 命名空间中的类高一些),System.Data.OracleClient 命名空间中的类要比 System.Data.OleDb 命名空间的类效率高一些(这一点我没有亲自验证,但大多数地方都会这么说,而且既然专门为 Oracle 作的东西理论上也应该专门作过针对性的优化)。</P>; l$ c* @2 X" f! k- ^$ W9 r
<>  当然还有另一点就是从针对性上说,System.Data.OracleClient 要更好一些:</P>
) c5 z2 }4 Y( e$ q<>  比如数据类型,System.Data.OleDb.OleDbType 枚举中所列的就没有 System.Data.OracleClient.OracleType 枚举中的那些有针对性;另外,Oracle 的Number 类型如果数字巨大,超出 .NET 数据类型范围的情况中,就必须使用System.Data.OracleClient 中的专门类 -- OracleNumber 类型。</P>
# q& [6 r. O" h- |$ }8 Z<>  好了,不再赘述这两个的比较,下面主要讨论System.Data.OracleClient 命名空间中的类型,即 ADO.NET for Oracle Data Provider (数据提供程序)。</P>! Z" {$ t: f$ C: k8 |
<>2。数据库连接:</P>( l7 Q" K# f8 k  B8 u  F
<>  无论是 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>
6 ~3 s1 t  C! a<>System Requirements:</P>. @: V$ W% Z: F5 L( S
<>  (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>
* \5 D! E( o# Y; m, J<>  (2)如用 System.Data.OleDb 访问 Oracle,客户端组件版本 7.3.3.4.0 以上或 8.1.7.4.1 以上。MDAC 2.6 以上。</P>
* g! Y/ k, l# s$ x  a0 d<>  如服务器为 Oracle8i 以上,客户端组件版本应为 8.0.4.1.1c。</P>
6 J" z, d: O6 ^<>  在 .NET 运行的机器中,安装 Oracle 客户端,然后打开 Net Manager (Oracle 9i) / Easy Config (Oracle 8i) 按你以前的经验设置本地服务的映射(这里的服务名将用于数据库连接串)。</P>
5 i- V: a" A9 f* |( U$ s& w# h* m' @: N<>  System.Data.OracleClient 中访问 Oracle 数据库的连接串是:</P>
! k2 h7 O8 V' l- j. l' X3 {0 U8 |1 O<>User ID=用户名; Password=密码; Data Source=服务名</P>6 [$ {* l* `# m% L/ g2 O  P  T
<>  (上述为一般的连接串,详细的连接串项目可以在 System.Data.OracleClient.OracleConnection.ConnectionString 属性的文档中找到。)</P>
+ _, u, Z/ E1 v' G2 ?/ W( w! r$ {<>  System.Data.OleDb 中的访问 Oracle 数据库的连接串是:</P>
; J, M; j0 S3 X( }- K6 b<>rovider=MSDAORA.1; User ID=用户名; Password=密码; Data Source=服务名</P>
& P" @7 P- O( X. E! T) J5 Q<>3。Oracle 中的数据类型:</P>
( g' ]: u5 Y  O+ `7 a& A  }<>  Oracle 的数据类型和 SQL Server 相比,要“奇怪”一些:SQL Server 的大多数据类型很容易找到 .NET 中比较接近的类型,Oracle 中的类型就离 .NET 类型远了许多,毕竟 Oracle 是和 Java 亲近的数据库。</P>
% e' _% J" @1 p" c& {2 q! c# hnumber: 数字类型,一般是 Number(M,N),M是有效数字,N是小数点后的位数(默认0),这个是按十进制说的。
% V0 K+ N  _  V7 V; Y6 f: s" Z% Onvarchar2: 可变长字符型(Unicode),这个比较像 SQL Server 的 nvarchar(但不知 Oracle 为什么加了个“2”)。(去掉“n”为非 Unicode 的,下同。)
# I  C( A/ n* M' C! T3 J/ B3 Knchar: 定长字符型(Unicode)。 8 C) t& F( n$ k0 L
nclob: “写作文”的字段,存储大量字符(Unicode)时用。 ' n0 c9 @6 V( ?
date: 日期类型,比较接近 SQL Server 的 datetime。
1 G' e' I5 W: R; [. p$ o  T<>  Oracle 中字段不能是 bit 或者 bool 之类的类型,一般是 number(1) 代替的。</P>
. h# P0 g" t8 R! F<>  和 SQL Server 一样在 SQL 命令中,字符类型需要用单引号(')隔开,两个单引号('')是单引号的字符转义(比如: I'm fat. 写入一个 SQL 命令是: UPDATE ... SET ...='I''m fat.' ...)。</P>
8 k% K/ v) |  q- \" m" W<>  比较特殊的是日期类型:比如要写入 2004-7-20 15:20:07 这个时刻需要如下写:</P>7 F' P- u; y% h3 O% r% g5 }
<>UPDATE ... SET ... = TIMESTAMP '2004-7-20 15:20:07' ...</P>
! n; k$ @6 p2 T+ `3 a" W. d2 C% K<>注意这里使用了 TIMESTAMP 关键字,并使用单引号隔开;另外请注意日期格式,上面的格式是可识别的,Oracle 识别的格式没有 SQL Server 那般多。这是和 SQL Server 不同的地方。</P>
* Z! M3 C. [. N/ _' p  n; k6 L6 O<>顺便提一句:Access 中的日期类型是用井号(#)隔开的,UPDATE ... SET ... = #2004-7-20 15:20:07# ...</P>3 e) D) j" |. l% ?+ k9 d7 H
<>4。访问 Oracle 过程/函数(1)</P>
$ ^% |0 |  F8 R+ Y4 G<>  SQL Server 作程序时经常使用存储过程,Oracle 里也可以使用过程,还可以使用函数。Oracle 的过程似乎是不能有返回值的,有返回值的就是函数了(这点有些像 BASIC,函数/过程区分的很细致。SQL Server 存储过程是可以有返回值的)。</P>4 J6 _$ Z  @# f$ B& F
<>.NET 访问 Oracle 过程/函数的方法很类似于 SQL Server,例如:</P>
: a) l2 d( u6 N0 W<>OracleParameter[] parameters = {
! m/ U/ H: V, j  d# g7 {    new OracleParameter("ReturnValue", OracleType.Int32, 0, ParameterDirection.ReturnValue, true, 0, 0, "",
3 B  M0 W0 B2 D* O( m         DataRowVersion.Default, Convert.DBNull )# l- G2 |) q5 Z- U
    new OracleParameter("参数1", OracleType.NVarChar, 10),
9 Z# Z3 t' |2 [( I0 V9 N/ s    new OracleParameter("参数2",  OracleType.DateTime),
9 [# U( ~. Z' i( V1 |    new OracleParameter("参数3",  OracleType.Number, 1)
# ]% k3 |1 A+ a, G9 s1 k/ `( k" B };9 M9 ]% ^' j, h2 I
/ ]1 T) h/ M. P: d  t
parameters[1].Value = "test";
" r% D% U$ w* A. J: a5 ^) @parameters[2].Value = DateTime.Now;
' @1 D/ i  v( Q& lparameters[3].Value = 1;                        // 也可以是 new OracleNumber(1);</P>
0 c  |1 W; T# |( |0 ^<P>OracleConnection connection = new OracleConnection( ConnectionString );; l2 @2 c8 n: l% A
OracleCommand command = new OracleCommand("函数/程名", connection);  W2 G% A$ t# o6 `( u
command.CommandType = CommandType.StoredProcedure;
4 R/ F8 I. o; [3 S1 j2 q/ f) Q
5 t% L& C. @5 h7 i7 j1 kforeach(OracleParameter parameter in parameters)5 o  N8 k* ^+ {2 X
     command.Parameters.Add( parameter );
# d. ?/ P7 D  y8 n0 E- T- b& B  ~* Y* k6 ^1 q1 X9 F1 `) L2 W: R% P
connection.Open();  U/ @1 I& q; Q& O4 z0 Q
command.ExecuteNonQuery();
- Y! [! g" M7 t0 W& ]1 ~int returnValue = parameters[0].Value; //接收函数返回值
8 A" X+ ^: k4 m: k- O; m; mconnection.Close();</P>/ P) Z3 _9 j8 a4 B  L
<P>  Parameter 的 DbType 设定请参见 System.Data.OracleClient.OracleType 枚举的文档,比如:Oracle 数据库中 Number 类型的参数的值可以用 .NET decimal 或 System.Data.OracleClient.OracleNumber 类型指定; Integer 类型的参数的值可以用 .NET int 或 OracleNumber 类型指定。等等。</P>
; {: g3 i% L' d! J+ y<P>  上面例子中已经看到函数返回值是用名为“ReturnValue”的参数指定的,该参数为 ParameterDirection.ReturnValue 的参数。</P>
& Z& {) Q* l: O- l  r* y: Y+ S<P>5。访问 Oracle 过程/函数 (2)</P>
, J5 G9 g, {3 r3 |4 }4 a5 ^<P>  不返回记录集(没有 SELECT 输出)的过程/函数,调用起来和 SQL Server 较为类似。但如果想通过过程/函数返回记录集,在 Oracle 中就比较麻烦一些了。</P>
  I5 i1 q4 y: a. w- l. m<P>在 SQL Server 中,如下的存储过程:</P>
! A5 k+ W/ x5 N& @( i9 w6 b<P>CREATE PROCEDURE GetCategoryBooks
/ Y( Z& C, }& x6 i  H(. Y! V* h1 `# B1 D$ Y+ W
    @CategoryID int' I$ r: Z' M9 T9 W& z4 [& n
)' F, I; o5 \; }  ^% p3 K9 A
AS
4 C4 t( {: i5 vSELECT * FROM Books3 y% J& c$ {* `# D* ]% H
WHERE CategoryID = @CategoryID* Z& W, I  y4 K6 X5 @! V, C# k
GO</P>" Y' ^2 N2 }$ L! b2 i; u6 l  Z
<P>  在 Oracle 中,请按以下步骤操作:</P>
8 F# U2 P9 t4 m<P>(1)创建一个包,含有一个游标类型:(一个数据库中只需作一次)</P>) H4 K$ N  A# [' L6 i5 W) y
<P>CREATE OR REPLACE PACKAGE Test
4 X( v- k  q' L; g  AS  z3 S$ f6 G+ t: q/ V* W, L
       TYPE Test_CURSOR IS REF CURSOR;
& Z5 j) k6 v% E' XEND Test;</P>
7 X9 B6 N2 r9 @& V+ S5 v* I<P>(2)过程:</P>( k+ d; t" f% b7 R/ D8 e- n. y
<P>CREATE OR REPLACE PROCEDURE GetCategoryBooks
* O  n2 O- @1 b) p0 L* W(
  F0 R- M7 M: H" ?6 H9 P     p_CURSOR out Test.Test_CURSOR,    -- 这里是上面包中的类型,输出参数$ I, f( l9 C0 }& p- ~. z
     p_CatogoryID INTEGER/ e- X* t3 _* A8 W* A) [8 p
)$ O/ @" ]5 V( P) H* t7 q
AS
! J' `1 G$ A( |+ e" ZBEGIN
. h1 G5 [% K; I7 P0 T; Y     OPEN p_CURSOR FOR# `9 x, K! z1 |: I$ J- L
           SELECT * FROM Books" Y1 p" N6 G0 {5 M8 f  ~
           WHERE CategoryID=p_CatogoryID;
# n4 I  X* R- }1 ZEND GetCategoryBooks;</P>$ ^& v; Z: `! U& }0 F8 W
<P>(3).NET 程序中:</P>
, `# ]; J( r9 n9 R3 x* Y3 g<P>OracleParameters parameters = {6 }" F  k. s2 g  E
     new OracleParameter("p_CURSOR", OracleType.CURSOR, 2000, ParameterDirection.Output, true, 0, 0, "",/ L2 V; s; e9 o& W5 f/ B
          DataRowVersion.Default, Convert.DBNull),
( `2 S+ ?" u2 Q; r/ {     new OracleParameter("p_CatogoryID", OracleType.Int32)
  E( L, {  W7 j+ d3 r, a};
9 R* e6 @8 T, ^  k
3 T# ~, r! b: `( ?% l! o. J( jparameters[1].Value = 22;
$ B4 C5 @1 L5 K+ [+ P- O- \
" l) {/ I+ w3 ], T4 \. @OracleConnection connection = new OracleConnection( ConnectionString );! v; Z, k$ ]: C. c: X  S6 B/ }
OracleCommand command = new OracleCommand("GetCategoryBooks", connection);
. q) n1 j8 n3 g# ?% Xcommand.CommandType = CommandType.StoredProcedure;
, R- y" Q" M5 J! r' r' z  y7 J# \# A+ g* I  w
foreach(OracleParameter parameter in parameters)* P" H( V: n/ Z. B
     command.Parameters.Add( parameter );
+ \9 U4 u8 Z  \* @# X! Q& D4 K5 h2 f
connection.Open();
! s* P) x: Q" [% H6 B  ~8 `1 m# }OracleDataReader dr = command.ExecuteReader();
4 y  Q; y/ P$ o8 R; N" j+ |) o! k) C; O% s3 U) r( k
while(dr.Read())
# i# @% L; O; `$ v$ `( C' ~{8 Z% y6 Z0 R) z0 C/ D& w9 Y5 Q
    // 你的具体操作。这个就不需要我教吧?
7 k9 G7 m3 x0 i: z* V/ a2 x6 e1 Q}' k8 n( {1 u8 f9 P
connection.Close();</P>
5 V" Q; {) G! ^* k, G0 `<P>  另外有一点需要指出的是,如果使用 DataReader 取得了一个记录集,那么在 DataReader 关闭之前,程序无法访问输出参数和返回值的数据。</P>' i1 d) ^; W7 h  [- A
<P>  好了,先这些,总之 .NET 访问 Oracle 还是有很多地方和 SQL Server 不同的,慢慢学习了。</P>
& g9 v) w+ p; Z1 L# ~<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-10-9 07:15 , Processed in 0.457773 second(s), 58 queries .

    回顶部