- 在线时间
- 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 的东西,发现问题倒真的不少。
: |0 ?- `8 q+ L) `% s7 [3 S< >& {8 C, L' t% ^
) y0 T( c$ K# O& [
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>* r) v$ D* q# o% ~) J
< > 虽然通过这两个命名空间的类都可以访问 Oracle 数据库,但和 SQL Server 类似的(System.Data.SqlClient 命名空间的类效率要比 System.Data.OleDb 命名空间中的类高一些),System.Data.OracleClient 命名空间中的类要比 System.Data.OleDb 命名空间的类效率高一些(这一点我没有亲自验证,但大多数地方都会这么说,而且既然专门为 Oracle 作的东西理论上也应该专门作过针对性的优化)。</P>5 S/ x0 m8 b8 b x4 A
< > 当然还有另一点就是从针对性上说,System.Data.OracleClient 要更好一些:</P>
) R7 U! ^! g! ?5 N5 }& r5 f< > 比如数据类型,System.Data.OleDb.OleDbType 枚举中所列的就没有 System.Data.OracleClient.OracleType 枚举中的那些有针对性;另外,Oracle 的Number 类型如果数字巨大,超出 .NET 数据类型范围的情况中,就必须使用System.Data.OracleClient 中的专门类 -- OracleNumber 类型。</P>
0 s. C" l( T/ a+ V Q: Q0 W" G< > 好了,不再赘述这两个的比较,下面主要讨论System.Data.OracleClient 命名空间中的类型,即 ADO.NET for Oracle Data Provider (数据提供程序)。</P>
6 m6 s- j' [! L- v+ `& t y< >2。数据库连接:</P>& M ^+ l: d" o3 [& ]
< > 无论是 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 b% l2 @, Q8 {" a) s3 S4 t% w, i* y< >System Requirements:</P>
* M* d( P. a! k( w1 B7 x; ^) k< > (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>
) {8 ]7 S8 ~, q. X- s9 h+ a< > (2)如用 System.Data.OleDb 访问 Oracle,客户端组件版本 7.3.3.4.0 以上或 8.1.7.4.1 以上。MDAC 2.6 以上。</P> w2 R$ D/ e7 v4 o: Z; J1 H& `9 F
< > 如服务器为 Oracle8i 以上,客户端组件版本应为 8.0.4.1.1c。</P>
% h, M, d' d+ b9 F< > 在 .NET 运行的机器中,安装 Oracle 客户端,然后打开 Net Manager (Oracle 9i) / Easy Config (Oracle 8i) 按你以前的经验设置本地服务的映射(这里的服务名将用于数据库连接串)。</P>+ F& X! _; j, i9 }. ]- C
< > System.Data.OracleClient 中访问 Oracle 数据库的连接串是:</P>7 W1 u( M5 w, L6 y- a4 _' Y- |
< >User ID=用户名; Password=密码; Data Source=服务名</P>
& ~3 H$ \% U9 P" G5 m< > (上述为一般的连接串,详细的连接串项目可以在 System.Data.OracleClient.OracleConnection.ConnectionString 属性的文档中找到。)</P>8 x h) S. l# P6 W) B" ]
< > System.Data.OleDb 中的访问 Oracle 数据库的连接串是:</P>% N1 E' E0 ?& t7 i: l$ B ^
< > rovider=MSDAORA.1; User ID=用户名; Password=密码; Data Source=服务名</P>: s6 r U% P+ r- o& d
< >3。Oracle 中的数据类型:</P>
9 V' X5 l/ N! o< > Oracle 的数据类型和 SQL Server 相比,要“奇怪”一些:SQL Server 的大多数据类型很容易找到 .NET 中比较接近的类型,Oracle 中的类型就离 .NET 类型远了许多,毕竟 Oracle 是和 Java 亲近的数据库。</P>+ ?" m1 [; Q& ]
number: 数字类型,一般是 Number(M,N),M是有效数字,N是小数点后的位数(默认0),这个是按十进制说的。
6 C1 [/ Y9 s) J! \$ Vnvarchar2: 可变长字符型(Unicode),这个比较像 SQL Server 的 nvarchar(但不知 Oracle 为什么加了个“2”)。(去掉“n”为非 Unicode 的,下同。) / W: Z# I6 G5 E8 O/ I7 U- d6 a
nchar: 定长字符型(Unicode)。 + b4 R+ `, A' H
nclob: “写作文”的字段,存储大量字符(Unicode)时用。 , p6 s" s6 u9 ?# W( m) b
date: 日期类型,比较接近 SQL Server 的 datetime。
- {: m! u6 {: U9 s< > Oracle 中字段不能是 bit 或者 bool 之类的类型,一般是 number(1) 代替的。</P>
! L. q( `& Y) x6 h$ J# Y# m< > 和 SQL Server 一样在 SQL 命令中,字符类型需要用单引号(')隔开,两个单引号('')是单引号的字符转义(比如: I'm fat. 写入一个 SQL 命令是: UPDATE ... SET ...='I''m fat.' ...)。</P>0 R0 u9 m+ u( s V& y
< > 比较特殊的是日期类型:比如要写入 2004-7-20 15:20:07 这个时刻需要如下写:</P>8 |# `" r1 `( h3 t' V
< >UPDATE ... SET ... = TIMESTAMP '2004-7-20 15:20:07' ...</P>: L# X9 Y. u/ P2 a& s" i+ D
< >注意这里使用了 TIMESTAMP 关键字,并使用单引号隔开;另外请注意日期格式,上面的格式是可识别的,Oracle 识别的格式没有 SQL Server 那般多。这是和 SQL Server 不同的地方。</P>
3 N3 W* C1 w5 {5 x: ^# v6 Q< >顺便提一句:Access 中的日期类型是用井号(#)隔开的,UPDATE ... SET ... = #2004-7-20 15:20:07# ...</P>
* b; ]( h7 C0 X# P s: Y m, f< >4。访问 Oracle 过程/函数(1)</P>7 Q4 r5 n" ?2 W+ O9 i) T
< > SQL Server 作程序时经常使用存储过程,Oracle 里也可以使用过程,还可以使用函数。Oracle 的过程似乎是不能有返回值的,有返回值的就是函数了(这点有些像 BASIC,函数/过程区分的很细致。SQL Server 存储过程是可以有返回值的)。</P>
/ ]3 n1 E9 l4 S1 M3 O< >.NET 访问 Oracle 过程/函数的方法很类似于 SQL Server,例如:</P>% z* j& C u- _1 d( F
< >OracleParameter[] parameters = {9 {2 m8 C0 w$ Y2 ]2 z" X* D
new OracleParameter("ReturnValue", OracleType.Int32, 0, ParameterDirection.ReturnValue, true, 0, 0, "",
* I8 f" U7 h5 J1 T# M- d DataRowVersion.Default, Convert.DBNull )% X/ m: w/ J% ]9 X+ ?1 a7 Z
new OracleParameter("参数1", OracleType.NVarChar, 10),7 @9 b& o/ n$ G* s# [
new OracleParameter("参数2", OracleType.DateTime),$ |, Q2 Z# h8 x5 E4 ^
new OracleParameter("参数3", OracleType.Number, 1)
0 k$ c5 O0 {7 F6 D; m; W: | };
& {! v0 c: P+ p$ e8 L" |7 d+ x# _) z* D
parameters[1].Value = "test";1 d( H0 q8 K" I! l/ m- E. Z
parameters[2].Value = DateTime.Now;
0 D8 f- W. K4 J& Pparameters[3].Value = 1; // 也可以是 new OracleNumber(1);</P>% Z" f& J' j* n
<P>OracleConnection connection = new OracleConnection( ConnectionString );
5 [* I# F" B7 Q+ V) _ \' K; _OracleCommand command = new OracleCommand("函数/程名", connection);. l+ d( j- b3 M
command.CommandType = CommandType.StoredProcedure;5 [ Q, o8 C, ]! }+ m
+ D8 w8 s7 {* y* n+ n
foreach(OracleParameter parameter in parameters)
' s- z; d2 z' S2 O0 N2 X, o- B5 ~ command.Parameters.Add( parameter );
: |! Z( H: N% z% I" A" x. R Q( f2 R
connection.Open();0 |6 Z" i% T& \3 H/ a
command.ExecuteNonQuery();% e6 s. r& `8 L: @1 o
int returnValue = parameters[0].Value; //接收函数返回值: H& g& W2 y! P
connection.Close();</P>! L$ A( l7 {# [' B% k& z7 w
<P> Parameter 的 DbType 设定请参见 System.Data.OracleClient.OracleType 枚举的文档,比如:Oracle 数据库中 Number 类型的参数的值可以用 .NET decimal 或 System.Data.OracleClient.OracleNumber 类型指定; Integer 类型的参数的值可以用 .NET int 或 OracleNumber 类型指定。等等。</P>, I3 _1 Y$ X1 [, i+ s3 d
<P> 上面例子中已经看到函数返回值是用名为“ReturnValue”的参数指定的,该参数为 ParameterDirection.ReturnValue 的参数。</P>
& w( U( v# w5 z) `# f( s! S8 o<P>5。访问 Oracle 过程/函数 (2)</P>
/ A2 b5 k% g" u3 U<P> 不返回记录集(没有 SELECT 输出)的过程/函数,调用起来和 SQL Server 较为类似。但如果想通过过程/函数返回记录集,在 Oracle 中就比较麻烦一些了。</P>
/ [$ a' \5 I+ ]0 i( u<P>在 SQL Server 中,如下的存储过程:</P>
' _; [; @3 ~1 @. p2 X' Q<P>CREATE PROCEDURE GetCategoryBooks7 {/ f: `1 }0 I, K8 p4 Q
(
2 Q. a5 y, @9 ~8 F, B( S @CategoryID int
. y( T9 U2 s1 b- R7 m" ^)" Z8 v' s0 b# d9 C: m
AS* x8 t+ V, |3 q. u# s8 F5 Y* o
SELECT * FROM Books3 U9 j( D P! o' k: r% Q! ]
WHERE CategoryID = @CategoryID
% k! _! t- K$ a2 H! J$ _GO</P>
, k8 x9 _6 S7 y* g4 |<P> 在 Oracle 中,请按以下步骤操作:</P>
: w0 f* M5 L9 k$ g5 ]; U0 p5 I/ A<P>(1)创建一个包,含有一个游标类型:(一个数据库中只需作一次)</P>2 N* Z# g9 O3 v/ T; x
<P>CREATE OR REPLACE PACKAGE Test
, h# W. ~2 e9 J( p9 K: k% b" ~ AS$ P6 C6 }. I7 u9 m! t& P6 w
TYPE Test_CURSOR IS REF CURSOR;
* d3 J# {- Q( O0 Z8 HEND Test;</P>
1 T( n5 U, D' @6 R6 [9 t<P>(2)过程:</P>
( V$ R- N9 s0 L: o<P>CREATE OR REPLACE PROCEDURE GetCategoryBooks
4 i, A2 j" r5 f3 C+ l" M(
/ i7 u9 d/ ]% W6 [) p p_CURSOR out Test.Test_CURSOR, -- 这里是上面包中的类型,输出参数, E5 ?6 [) L' y/ I9 m# {
p_CatogoryID INTEGER6 Q6 s! `* m U4 T5 g" u
)
7 ^; c( Y4 X6 EAS
8 |+ u6 w# }* XBEGIN
" q2 l$ z+ `0 k. B! d5 J OPEN p_CURSOR FOR1 J: i' z- x$ A5 v0 [: D
SELECT * FROM Books5 p% M) {6 n0 r6 A
WHERE CategoryID=p_CatogoryID;
* P" ^2 \( M" c+ B2 c5 lEND GetCategoryBooks;</P>/ ?$ K& J+ U# d7 z1 T
<P>(3).NET 程序中:</P>4 k. M% I# [5 u4 y
<P>OracleParameters parameters = {/ n' F- B3 r. Z$ b5 ^
new OracleParameter("p_CURSOR", OracleType.CURSOR, 2000, ParameterDirection.Output, true, 0, 0, "",
( Q7 R0 g% {" E3 t6 ^ DataRowVersion.Default, Convert.DBNull),
+ g2 R' j5 }4 E6 ^/ S. V$ I new OracleParameter("p_CatogoryID", OracleType.Int32)
" _8 X, Q3 S8 y' s! h1 v7 z};
6 ^# w$ ~. @ H- h& d" ]
" f8 U; Z n7 X' |* N3 aparameters[1].Value = 22;
`# F, c0 k' G% V' K# _
' Y0 U6 g6 H5 v3 K# ?5 B1 qOracleConnection connection = new OracleConnection( ConnectionString );
" e* @4 U: u1 @, O( MOracleCommand command = new OracleCommand("GetCategoryBooks", connection);' q7 J |. w/ b, {# p& K
command.CommandType = CommandType.StoredProcedure;
$ |! Z# v, |9 r* W" g: F1 B l2 ]7 e g" R( L2 Q9 u
foreach(OracleParameter parameter in parameters)
- l4 B4 t# [! e3 M4 ?) X, k( V command.Parameters.Add( parameter );, D( b& J0 @. j" [ A6 R) t: x+ }
! B+ C9 K4 g4 {% ?& j9 P* q
connection.Open();
. F1 A: x0 K1 A6 ?; oOracleDataReader dr = command.ExecuteReader();$ F3 l" ^3 T! P6 e6 M1 ^) Z$ Y
! \5 o3 c# u6 d6 L8 y; z3 h: q
while(dr.Read()); ~* v! U2 W/ L( o% A" v9 `% C
{8 L: F3 `& j# t7 P: _4 n7 q/ _0 f
// 你的具体操作。这个就不需要我教吧?$ ]3 N1 M% m0 g6 s
}
. x2 L7 ?7 C% E: i+ l: ^$ `" pconnection.Close();</P>
, @/ a+ }, w. y, h5 {1 W<P> 另外有一点需要指出的是,如果使用 DataReader 取得了一个记录集,那么在 DataReader 关闭之前,程序无法访问输出参数和返回值的数据。</P>
x7 @! h8 U# u7 O<P> 好了,先这些,总之 .NET 访问 Oracle 还是有很多地方和 SQL Server 不同的,慢慢学习了。</P>
8 M. r8 s5 m0 Y n<P> |
zan
|