- 在线时间
- 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 的东西,发现问题倒真的不少。 + M. _5 F! @: E" S6 \
< >
: O+ D: l7 D$ _0 a% d6 {& R6 W0 B* ~. {& b. Q, y
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>
- m6 t2 O4 H, L, y3 F2 p< > 虽然通过这两个命名空间的类都可以访问 Oracle 数据库,但和 SQL Server 类似的(System.Data.SqlClient 命名空间的类效率要比 System.Data.OleDb 命名空间中的类高一些),System.Data.OracleClient 命名空间中的类要比 System.Data.OleDb 命名空间的类效率高一些(这一点我没有亲自验证,但大多数地方都会这么说,而且既然专门为 Oracle 作的东西理论上也应该专门作过针对性的优化)。</P>) Z7 t" S7 w- D- P. B
< > 当然还有另一点就是从针对性上说,System.Data.OracleClient 要更好一些:</P>
- s& _% z& W( R2 S0 y7 ]< > 比如数据类型,System.Data.OleDb.OleDbType 枚举中所列的就没有 System.Data.OracleClient.OracleType 枚举中的那些有针对性;另外,Oracle 的Number 类型如果数字巨大,超出 .NET 数据类型范围的情况中,就必须使用System.Data.OracleClient 中的专门类 -- OracleNumber 类型。</P>
9 @+ l# c& I; F7 d) f; I< > 好了,不再赘述这两个的比较,下面主要讨论System.Data.OracleClient 命名空间中的类型,即 ADO.NET for Oracle Data Provider (数据提供程序)。</P>( Z5 s, e6 d5 G
< >2。数据库连接:</P>
1 D5 j$ W, Q8 d2 j7 r2 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>) f) h4 p* k" t, d) c
< >System Requirements:</P># X7 ~) ]% n( w D, N" \
< > (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>
* Z) l: x2 R! ?# k0 p( b' h< > (2)如用 System.Data.OleDb 访问 Oracle,客户端组件版本 7.3.3.4.0 以上或 8.1.7.4.1 以上。MDAC 2.6 以上。</P>1 a$ p- M9 o1 Q) Z" A3 O3 p Z
< > 如服务器为 Oracle8i 以上,客户端组件版本应为 8.0.4.1.1c。</P>
9 z( D# R b& F' t, T- G< > 在 .NET 运行的机器中,安装 Oracle 客户端,然后打开 Net Manager (Oracle 9i) / Easy Config (Oracle 8i) 按你以前的经验设置本地服务的映射(这里的服务名将用于数据库连接串)。</P>! U) K. ` f+ ^$ ^; F2 y6 ~* _
< > System.Data.OracleClient 中访问 Oracle 数据库的连接串是:</P>5 G. x9 n5 f7 V+ [, l2 v: X$ N
< >User ID=用户名; Password=密码; Data Source=服务名</P>
: j* ^" z4 e. A$ V4 @/ s% j< > (上述为一般的连接串,详细的连接串项目可以在 System.Data.OracleClient.OracleConnection.ConnectionString 属性的文档中找到。)</P>' A1 \* p: ~& \$ V; U( @) y' ]
< > System.Data.OleDb 中的访问 Oracle 数据库的连接串是:</P>5 t% N" d: }$ {+ L0 Y+ B
< > rovider=MSDAORA.1; User ID=用户名; Password=密码; Data Source=服务名</P>
; Q- \' f! `* M8 @< >3。Oracle 中的数据类型:</P>
+ S* @1 T/ B" V8 q5 k< > Oracle 的数据类型和 SQL Server 相比,要“奇怪”一些:SQL Server 的大多数据类型很容易找到 .NET 中比较接近的类型,Oracle 中的类型就离 .NET 类型远了许多,毕竟 Oracle 是和 Java 亲近的数据库。</P>, k0 y: b6 f# K5 {7 m# v; c# Q
number: 数字类型,一般是 Number(M,N),M是有效数字,N是小数点后的位数(默认0),这个是按十进制说的。
. j7 J( r5 ~4 A: U$ b3 K# fnvarchar2: 可变长字符型(Unicode),这个比较像 SQL Server 的 nvarchar(但不知 Oracle 为什么加了个“2”)。(去掉“n”为非 Unicode 的,下同。) 8 z0 ^: ? N; N# l. P/ F
nchar: 定长字符型(Unicode)。 , j5 ^. o& L) w
nclob: “写作文”的字段,存储大量字符(Unicode)时用。 + A1 P. M; E1 |$ n, k
date: 日期类型,比较接近 SQL Server 的 datetime。/ T- v2 w! @2 D! X& y
< > Oracle 中字段不能是 bit 或者 bool 之类的类型,一般是 number(1) 代替的。</P>7 G) s& C9 X' t! L; T
< > 和 SQL Server 一样在 SQL 命令中,字符类型需要用单引号(')隔开,两个单引号('')是单引号的字符转义(比如: I'm fat. 写入一个 SQL 命令是: UPDATE ... SET ...='I''m fat.' ...)。</P>
& t; i8 |* A0 N/ s3 L< > 比较特殊的是日期类型:比如要写入 2004-7-20 15:20:07 这个时刻需要如下写:</P>
: e3 G0 d1 C2 Y3 @/ p; F< >UPDATE ... SET ... = TIMESTAMP '2004-7-20 15:20:07' ...</P>
* d, c0 u" n' F< >注意这里使用了 TIMESTAMP 关键字,并使用单引号隔开;另外请注意日期格式,上面的格式是可识别的,Oracle 识别的格式没有 SQL Server 那般多。这是和 SQL Server 不同的地方。</P>" E* m, f8 Q" N! w }
< >顺便提一句:Access 中的日期类型是用井号(#)隔开的,UPDATE ... SET ... = #2004-7-20 15:20:07# ...</P>
2 Q5 n+ t( k) ]! N( \" O/ M) X< >4。访问 Oracle 过程/函数(1)</P>
/ D- D: b' T F6 G< > SQL Server 作程序时经常使用存储过程,Oracle 里也可以使用过程,还可以使用函数。Oracle 的过程似乎是不能有返回值的,有返回值的就是函数了(这点有些像 BASIC,函数/过程区分的很细致。SQL Server 存储过程是可以有返回值的)。</P>( A$ p }* b& n7 ?: H
< >.NET 访问 Oracle 过程/函数的方法很类似于 SQL Server,例如:</P>
" G0 b. K% K' R# L- c7 ]% x' b< >OracleParameter[] parameters = {
% f H; J% O) m( [2 Z new OracleParameter("ReturnValue", OracleType.Int32, 0, ParameterDirection.ReturnValue, true, 0, 0, "",8 D; Y5 v! t0 j( u5 w: V& @
DataRowVersion.Default, Convert.DBNull )3 L4 n9 q; g7 S( ~( w
new OracleParameter("参数1", OracleType.NVarChar, 10),; M5 o5 l* q# ^! r2 V( j
new OracleParameter("参数2", OracleType.DateTime),6 g O( F* J% K/ j
new OracleParameter("参数3", OracleType.Number, 1)
! h/ @% N" N: K };
2 Z' i/ ` f7 x8 b
% Y! n0 G- v" U& s' g) a: p$ u9 Aparameters[1].Value = "test";# ^7 a$ X9 p0 { F. m7 M0 f
parameters[2].Value = DateTime.Now;
9 F) M$ ^7 r3 G8 _) tparameters[3].Value = 1; // 也可以是 new OracleNumber(1);</P> c" w1 O5 k9 I* ?2 J# N" r
<P>OracleConnection connection = new OracleConnection( ConnectionString );
8 A, ^( W5 ]7 O( Q. wOracleCommand command = new OracleCommand("函数/程名", connection);% M& Q6 G. { [
command.CommandType = CommandType.StoredProcedure;6 s( p* L0 W3 _, k+ ~2 @0 q
# _, b: V! p1 r1 F+ v Oforeach(OracleParameter parameter in parameters); c+ F p/ o# M2 B& T2 k# |
command.Parameters.Add( parameter );. D1 g2 C5 |$ K
. T0 y6 r( a6 ?" Bconnection.Open(); [, F2 t0 U1 x, l
command.ExecuteNonQuery();. C5 e: c/ U0 J4 c/ l r5 B+ X& M
int returnValue = parameters[0].Value; //接收函数返回值
1 O% [* |* ?4 r; P+ pconnection.Close();</P>$ N. u* A2 B: m( O ? |
<P> Parameter 的 DbType 设定请参见 System.Data.OracleClient.OracleType 枚举的文档,比如:Oracle 数据库中 Number 类型的参数的值可以用 .NET decimal 或 System.Data.OracleClient.OracleNumber 类型指定; Integer 类型的参数的值可以用 .NET int 或 OracleNumber 类型指定。等等。</P># {, M0 ]" I6 V: ~3 y
<P> 上面例子中已经看到函数返回值是用名为“ReturnValue”的参数指定的,该参数为 ParameterDirection.ReturnValue 的参数。</P>7 b1 q/ Q! M4 x) X3 k: C2 z
<P>5。访问 Oracle 过程/函数 (2)</P>
& b8 w! q& C% L$ A$ T1 \5 h<P> 不返回记录集(没有 SELECT 输出)的过程/函数,调用起来和 SQL Server 较为类似。但如果想通过过程/函数返回记录集,在 Oracle 中就比较麻烦一些了。</P>
% \' M: S* B( u" t4 O* G5 D<P>在 SQL Server 中,如下的存储过程:</P>- A2 p# t" t- H" O3 ?8 O8 H
<P>CREATE PROCEDURE GetCategoryBooks6 [# @, K6 v7 K( T# [( [* u
(! |" g2 N. ]) [: w4 x8 j6 ?2 j1 V
@CategoryID int& z# L3 z/ W' J* K5 N& `
)) \( \' o' j$ `# m' K# O# S, z
AS& k _% \* i- n
SELECT * FROM Books
* p: c o7 f2 F! B$ n) F7 hWHERE CategoryID = @CategoryID
/ a6 s3 {2 D h4 U2 o& L- tGO</P> V9 a6 G; f& t$ z. ?& ?3 a
<P> 在 Oracle 中,请按以下步骤操作:</P>
$ L; A! \& G! I: k7 K+ u7 ]<P>(1)创建一个包,含有一个游标类型:(一个数据库中只需作一次)</P> c9 ^9 t) y3 \! W6 ]# x6 y, i
<P>CREATE OR REPLACE PACKAGE Test& E+ I' a2 \. q0 Q" h$ ?
AS g# W/ ?% a5 v+ j7 J$ [$ r
TYPE Test_CURSOR IS REF CURSOR;
, m( z* R: F' V; hEND Test;</P>6 b; B7 Q- ?) ~8 D/ Z
<P>(2)过程:</P>
: l' l/ U* b5 T& s; `0 v<P>CREATE OR REPLACE PROCEDURE GetCategoryBooks: t7 S7 P- J+ D: X) e
(! N( M# ^% s$ i2 I5 T
p_CURSOR out Test.Test_CURSOR, -- 这里是上面包中的类型,输出参数5 r- z5 L+ W# Y/ G1 r3 v
p_CatogoryID INTEGER1 I* `, E B1 @1 x8 H+ `% q0 r* _
)# F2 [" ~ K+ a! M, J
AS
6 P1 [2 X1 P" q$ M( _BEGIN# K# B& L: j# V) Z" k( r
OPEN p_CURSOR FOR8 f9 d% c) |9 z6 }" w
SELECT * FROM Books+ h4 w7 N5 S3 d: Z
WHERE CategoryID=p_CatogoryID;% R7 \- _( x3 k
END GetCategoryBooks;</P>
/ s+ l1 X- ^$ T, R! ^<P>(3).NET 程序中:</P>
4 P* j& F/ g( ?8 Z$ X) H" ~) v<P>OracleParameters parameters = {
, q' t+ ^+ K/ U5 o" p new OracleParameter("p_CURSOR", OracleType.CURSOR, 2000, ParameterDirection.Output, true, 0, 0, "",
_# ]5 y& c( }7 M* q5 ? DataRowVersion.Default, Convert.DBNull),
1 i5 J- O: _8 @: ]+ ?; _; @ new OracleParameter("p_CatogoryID", OracleType.Int32)9 i8 d1 b" y4 ?$ A# Y) s
};
1 I' b% W" w: `6 u, G: }3 }
, x$ }$ `4 w; |parameters[1].Value = 22;, Z% I0 h: A9 ]" ]( h
% J; d$ Q, \+ z# P |OracleConnection connection = new OracleConnection( ConnectionString );
& `* U) u5 f/ Q6 VOracleCommand command = new OracleCommand("GetCategoryBooks", connection);
: {) d) f2 @( icommand.CommandType = CommandType.StoredProcedure;4 K. O; M( L0 k. f
* M$ w# ?5 `8 [2 vforeach(OracleParameter parameter in parameters)
. {! a+ F$ _- Y, i" V: [1 J command.Parameters.Add( parameter );& i) F) O: `7 n' v
$ n z6 n) F7 y$ O, z3 [9 h. Gconnection.Open();
" u6 A/ `6 P) I2 d5 C5 A) SOracleDataReader dr = command.ExecuteReader();2 _ P; F. u* L6 ~3 d G/ _7 Y! P
: F2 n8 ^" Y+ |
while(dr.Read()) K) a/ R- l1 E+ p% w3 S& r' M+ N# b
{
, N8 F! G0 Z5 @$ k6 A // 你的具体操作。这个就不需要我教吧?
" z" }5 p* j9 P( U; N, o( g}
7 I- E* Q' W4 K0 i4 cconnection.Close();</P>
1 A( z+ \& ~- y<P> 另外有一点需要指出的是,如果使用 DataReader 取得了一个记录集,那么在 DataReader 关闭之前,程序无法访问输出参数和返回值的数据。</P>$ o6 V6 z ]! y- s, M3 r
<P> 好了,先这些,总之 .NET 访问 Oracle 还是有很多地方和 SQL Server 不同的,慢慢学习了。</P>
, W' z) v2 E. ~( J o<P> |
zan
|