QQ登录

只需要一步,快速开始

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

通过.NET访问 Oracle数据库

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-3 21:16 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
长期以来,我一直用的是 MS SQL Server / Access 数据库,通过.NET 访问MS自家的东西几乎没碰到过什么麻烦。最近项目中要用 Oracle 作为数据库,学习研究了一些 .NET 访问Oracle 的东西,发现问题倒真的不少。
6 ]4 V5 w+ j9 e% r9 g4 Z7 T<>
% g+ |/ m3 J: s
; V/ [. E, |; q* u; J2 J7 D; tflash/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>$ n( P: L( ?; _' G& f
<>  虽然通过这两个命名空间的类都可以访问 Oracle 数据库,但和 SQL Server 类似的(System.Data.SqlClient 命名空间的类效率要比 System.Data.OleDb 命名空间中的类高一些),System.Data.OracleClient 命名空间中的类要比 System.Data.OleDb 命名空间的类效率高一些(这一点我没有亲自验证,但大多数地方都会这么说,而且既然专门为 Oracle 作的东西理论上也应该专门作过针对性的优化)。</P>
* G( k& [+ A- F; N( D8 U( R/ G<>  当然还有另一点就是从针对性上说,System.Data.OracleClient 要更好一些:</P>
( j' K# D7 Y  z" I/ y* T7 g; S<>  比如数据类型,System.Data.OleDb.OleDbType 枚举中所列的就没有 System.Data.OracleClient.OracleType 枚举中的那些有针对性;另外,Oracle 的Number 类型如果数字巨大,超出 .NET 数据类型范围的情况中,就必须使用System.Data.OracleClient 中的专门类 -- OracleNumber 类型。</P>
& T# G9 ^  a; [; v1 U+ S5 O' G<>  好了,不再赘述这两个的比较,下面主要讨论System.Data.OracleClient 命名空间中的类型,即 ADO.NET for Oracle Data Provider (数据提供程序)。</P>
8 `# Q0 x+ z% m' ?" U<>2。数据库连接:</P>: L2 s4 J1 [# T% J' v4 B9 d: M
<>  无论是 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>/ b+ h2 C" Y2 Y. D  V0 R% P. u
<>System Requirements:</P>, I0 F0 Y7 z+ ?5 }4 b' 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>+ T: g2 U; |: g1 t
<>  (2)如用 System.Data.OleDb 访问 Oracle,客户端组件版本 7.3.3.4.0 以上或 8.1.7.4.1 以上。MDAC 2.6 以上。</P>
/ I" e  ]+ s' V7 {8 [+ E<>  如服务器为 Oracle8i 以上,客户端组件版本应为 8.0.4.1.1c。</P>
* \3 {# X3 F! A! a7 I: l<>  在 .NET 运行的机器中,安装 Oracle 客户端,然后打开 Net Manager (Oracle 9i) / Easy Config (Oracle 8i) 按你以前的经验设置本地服务的映射(这里的服务名将用于数据库连接串)。</P>% A0 T% E/ w! D  q* f3 ^1 ^( W% c
<>  System.Data.OracleClient 中访问 Oracle 数据库的连接串是:</P>
/ y0 j; E) M0 M3 r2 T" T* L<>User ID=用户名; Password=密码; Data Source=服务名</P>
  }4 y! }& H2 k  S) W1 k<>  (上述为一般的连接串,详细的连接串项目可以在 System.Data.OracleClient.OracleConnection.ConnectionString 属性的文档中找到。)</P>
  r9 `: P# {# O7 X; r7 S4 Q" @  l  a<>  System.Data.OleDb 中的访问 Oracle 数据库的连接串是:</P>
9 k& k! r; y  u, u( H<>rovider=MSDAORA.1; User ID=用户名; Password=密码; Data Source=服务名</P>
/ n* N4 w0 Y- P+ B# N<>3。Oracle 中的数据类型:</P>
) T3 F* X1 z$ g9 j- h1 w<>  Oracle 的数据类型和 SQL Server 相比,要“奇怪”一些:SQL Server 的大多数据类型很容易找到 .NET 中比较接近的类型,Oracle 中的类型就离 .NET 类型远了许多,毕竟 Oracle 是和 Java 亲近的数据库。</P>
% Y  K. q; q8 }number: 数字类型,一般是 Number(M,N),M是有效数字,N是小数点后的位数(默认0),这个是按十进制说的。 + j* |3 i" B& |+ t9 E
nvarchar2: 可变长字符型(Unicode),这个比较像 SQL Server 的 nvarchar(但不知 Oracle 为什么加了个“2”)。(去掉“n”为非 Unicode 的,下同。)
- t5 F/ h6 ?( {- lnchar: 定长字符型(Unicode)。
7 M6 H0 w  ~, J5 Lnclob: “写作文”的字段,存储大量字符(Unicode)时用。 8 U4 \' V/ `/ l# q! X. a
date: 日期类型,比较接近 SQL Server 的 datetime。
" p6 F8 \; X- R3 _, g<>  Oracle 中字段不能是 bit 或者 bool 之类的类型,一般是 number(1) 代替的。</P>; g" S+ }. B: ^3 _
<>  和 SQL Server 一样在 SQL 命令中,字符类型需要用单引号(')隔开,两个单引号('')是单引号的字符转义(比如: I'm fat. 写入一个 SQL 命令是: UPDATE ... SET ...='I''m fat.' ...)。</P>
( f4 [2 ]; q0 q<>  比较特殊的是日期类型:比如要写入 2004-7-20 15:20:07 这个时刻需要如下写:</P>
" @- y! L  b# C<>UPDATE ... SET ... = TIMESTAMP '2004-7-20 15:20:07' ...</P>
4 Q! i( T8 L) e8 U! |; Y* ~<>注意这里使用了 TIMESTAMP 关键字,并使用单引号隔开;另外请注意日期格式,上面的格式是可识别的,Oracle 识别的格式没有 SQL Server 那般多。这是和 SQL Server 不同的地方。</P>/ ~5 P: ]! @' [, ?( D
<>顺便提一句:Access 中的日期类型是用井号(#)隔开的,UPDATE ... SET ... = #2004-7-20 15:20:07# ...</P>$ r! T1 s9 i7 K
<>4。访问 Oracle 过程/函数(1)</P>& n  J9 o* o; [. K, ]! N
<>  SQL Server 作程序时经常使用存储过程,Oracle 里也可以使用过程,还可以使用函数。Oracle 的过程似乎是不能有返回值的,有返回值的就是函数了(这点有些像 BASIC,函数/过程区分的很细致。SQL Server 存储过程是可以有返回值的)。</P>
( ^% ~! V! q% t- T3 Z; d$ S+ N6 y7 K$ E<>.NET 访问 Oracle 过程/函数的方法很类似于 SQL Server,例如:</P>0 y4 o9 `" ?/ t- u. X- ]
<>OracleParameter[] parameters = {
- Y# V; g5 @4 V) }9 ?3 O2 b    new OracleParameter("ReturnValue", OracleType.Int32, 0, ParameterDirection.ReturnValue, true, 0, 0, "",5 ^. k4 c& V6 G: e; ?8 Q
         DataRowVersion.Default, Convert.DBNull )* @; ]. f8 [4 Q: u2 C9 \
    new OracleParameter("参数1", OracleType.NVarChar, 10),- j3 g, ?, g* l4 n
    new OracleParameter("参数2",  OracleType.DateTime),
; _8 `$ C, N9 a# l5 c, k7 ^$ o    new OracleParameter("参数3",  OracleType.Number, 1): X2 K$ o; p, ]7 Y
};
9 L3 h- c8 J& X9 p9 t) m* A9 B* F! D6 y( `, r) e9 L  m
parameters[1].Value = "test";& j0 P( w7 @. f) {0 I9 T
parameters[2].Value = DateTime.Now;! ~2 `1 V: X& c) U# f9 d  q$ @; q/ s
parameters[3].Value = 1;                        // 也可以是 new OracleNumber(1);</P>
# [) k9 f! }% [% r/ o<P>OracleConnection connection = new OracleConnection( ConnectionString );
3 l. x) B4 K1 e* P, w: S% l3 uOracleCommand command = new OracleCommand("函数/程名", connection);
# R0 C3 F9 Y  [$ d4 P  b! p) ~" J* vcommand.CommandType = CommandType.StoredProcedure;
( p2 w0 }; B. O; `) w0 d& r/ ?3 x5 i8 @/ l9 L9 h
foreach(OracleParameter parameter in parameters)) g- a9 f  K8 B- s" g+ e3 V
     command.Parameters.Add( parameter );
+ R" J8 Q6 P2 X# I! {( H
4 R; `1 `: o% g6 k7 N5 B' ]: ?connection.Open();
: b5 ~* ^( _4 `command.ExecuteNonQuery();
. z% u& k1 r" s- qint returnValue = parameters[0].Value; //接收函数返回值6 q* M# [0 R3 C; l! L
connection.Close();</P>5 T1 w9 J1 c8 d
<P>  Parameter 的 DbType 设定请参见 System.Data.OracleClient.OracleType 枚举的文档,比如:Oracle 数据库中 Number 类型的参数的值可以用 .NET decimal 或 System.Data.OracleClient.OracleNumber 类型指定; Integer 类型的参数的值可以用 .NET int 或 OracleNumber 类型指定。等等。</P>. S. a2 {2 U: m  e6 `
<P>  上面例子中已经看到函数返回值是用名为“ReturnValue”的参数指定的,该参数为 ParameterDirection.ReturnValue 的参数。</P>9 B0 F8 x0 @  v" L, l
<P>5。访问 Oracle 过程/函数 (2)</P>; u2 k1 B0 x" b
<P>  不返回记录集(没有 SELECT 输出)的过程/函数,调用起来和 SQL Server 较为类似。但如果想通过过程/函数返回记录集,在 Oracle 中就比较麻烦一些了。</P>
' f: ^( }  `3 t1 r% q9 q1 t3 b<P>在 SQL Server 中,如下的存储过程:</P>( d& O" w+ }2 ^
<P>CREATE PROCEDURE GetCategoryBooks2 P8 z# y( Q& Z( b
(2 P3 r% b4 ?- S( [2 ]% o
    @CategoryID int
+ Q9 a: ]: m* a( c' H)4 f' `) e% C1 s0 C8 @( l
AS2 I# O, D0 U- ]& [5 i/ `' }+ E7 B" G
SELECT * FROM Books6 R1 V+ J9 R4 N5 Q2 K
WHERE CategoryID = @CategoryID% O$ I$ a4 E' q$ u! S& G
GO</P>
6 p: F, F: _0 ^2 Q1 O( ?+ b% d<P>  在 Oracle 中,请按以下步骤操作:</P>0 ~9 ]" _& d. y5 d  {
<P>(1)创建一个包,含有一个游标类型:(一个数据库中只需作一次)</P>- `$ y  R0 ~. g
<P>CREATE OR REPLACE PACKAGE Test0 j5 |4 Z- E9 V  J2 j  [
  AS& D; d- Q9 x- b% K0 _9 ]$ o
       TYPE Test_CURSOR IS REF CURSOR;
$ g' e; U0 U6 ^% pEND Test;</P>
" e& b3 ~& _' a) j<P>(2)过程:</P>
, n. X* @1 I; a7 P/ V# t) Q<P>CREATE OR REPLACE PROCEDURE GetCategoryBooks1 ^, ]) g0 \$ {3 p* N
(  D1 p( q$ S1 u% X$ N, R
     p_CURSOR out Test.Test_CURSOR,    -- 这里是上面包中的类型,输出参数
: n- o4 k1 N7 z; _  e; k     p_CatogoryID INTEGER% c/ Q; I: }" K  F3 l( `
)
" c& ~' }5 q+ t. |% KAS
3 R2 _4 Q/ l% L, rBEGIN
: }9 `- a" a" v6 i+ i     OPEN p_CURSOR FOR) \, Z* M6 K4 S9 H6 w! Y+ s0 y
           SELECT * FROM Books
. }' E/ ^+ H) s' i5 r           WHERE CategoryID=p_CatogoryID;
, z2 B. i; Z" W9 a+ M0 [END GetCategoryBooks;</P>
8 ~, [* b: |5 J( F( W9 ~: _<P>(3).NET 程序中:</P>' j$ h8 U0 ~' v
<P>OracleParameters parameters = {
- T/ Z& T/ [1 z# J. R& M1 u) }$ v     new OracleParameter("p_CURSOR", OracleType.CURSOR, 2000, ParameterDirection.Output, true, 0, 0, ""," ^+ n& ^- R# ^. {1 j: o8 [
          DataRowVersion.Default, Convert.DBNull),! X( R, M, B1 o7 n. H" s6 x
     new OracleParameter("p_CatogoryID", OracleType.Int32): U/ L0 t. ]! ?9 Q
};
' r" T4 F" ?( z* m+ g5 j$ o% Z& b" z# w5 v& q+ Q4 ]; W9 [
parameters[1].Value = 22;
0 c) i  ^0 c4 |+ k: N- l5 v7 D. Y
2 Z% J  m* C% M: p: |) |OracleConnection connection = new OracleConnection( ConnectionString );0 U$ p( k( w$ o5 H
OracleCommand command = new OracleCommand("GetCategoryBooks", connection);0 l7 G( l7 M9 u
command.CommandType = CommandType.StoredProcedure;
' @' t$ i7 O8 y# B& f+ J' W' Q* n. B" ~2 e& ]
foreach(OracleParameter parameter in parameters)
# O! @, l! W. {* `9 @6 V4 U) m) R; T     command.Parameters.Add( parameter );
7 e3 t* Q* e3 N
+ Y/ |( c# |* y1 N# fconnection.Open();: j! X2 y1 h/ M( Y+ B) |  s7 Z
OracleDataReader dr = command.ExecuteReader();. T* w) o( p/ j- T' p
4 c" x9 n: u" m+ v. P/ f; i
while(dr.Read())
5 k6 i) W7 f7 H3 e9 d" ^{. ^0 v0 x# K5 Q! K0 t( `( {
    // 你的具体操作。这个就不需要我教吧?; ?2 N0 h) z7 F( K! N' i- F' e# n
}
$ _! j, c; W0 X: m: j% xconnection.Close();</P>
. r% P! v2 q3 e- Q<P>  另外有一点需要指出的是,如果使用 DataReader 取得了一个记录集,那么在 DataReader 关闭之前,程序无法访问输出参数和返回值的数据。</P>& i. E4 ]  [9 R( R
<P>  好了,先这些,总之 .NET 访问 Oracle 还是有很多地方和 SQL Server 不同的,慢慢学习了。</P>% F, ~& v) e% Z* Y3 U: Y
<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-8-10 02:12 , Processed in 0.404128 second(s), 58 queries .

    回顶部