一、Oracle XE 数据库与连接工具安装使用
Oracle数据库历来以价格昂贵出名,当然贵有贵的道理,成为一个Oracle DBA也是令人羡慕的事情,如果程序员熟悉Oracle使用也有机会接触到大型的项目,但是Oracle似乎对一般程序员不怎么友好,因为其繁琐的安装配置过程和对系统硬件的苛求,另一般人望而止步,我最早从Oracle 9i开始接触它,深有感受,特别是熟悉了sqlServer的开发人员,初次接触Oracle还是很不习惯的。比如它没有sqlServer数据“库”的概念,一个sa账号管理很多数据库,在Oracle里面,它叫做“数据服务”,通过不同的数据库用户来区分数据。
1.1 数据库服务安装
现在,Oracle推出了一个免费的数据库产品,Database 快捷版 11g ,这个就像sqlServer Express版本一样,都是免费的,与收费版在功能没有任何区别,但是有些使用条件限制,比如仅支持一个cpu,数据文件组大小有限制等,但是一般中小企业的一些中小应用还是够了。Database 快捷版 11g下载地址请点击这里。不过下载之前要先注册Oracle账号,并同意下载许可声明。
适用于 Windows x64 的 Oracle Database 快捷版 11g 第 2 版 | |
- 解压缩下载文件,然后运行 DISK1/setup.exe | |
适用于 Windows x32 的 Oracle Database 快捷版 11g 第 2 版 | |
- 解压缩下载文件,然后运行 DISK1/setup.exe | |
适用于 Linux x64 的 Oracle Database 快捷版 11g 第 2 版 - 解压缩下载文件,可以像往常一样安装 RPM 文件 |
根据你的情况,选择下载32位的或者64位的,我下载了64位的,安装很简单,中途没有什么特别注意的地方,一路“下一步” 即可,这比起Oracle其他版本的数据库安装来说,实在很简单,安装完成后,即可使用了,不过千万记住不要忘记了Sys,System 用户的密码。安装完成之后,在桌面会有一个快捷方式:Oracle Database 11g Express Edition 入门 ,单击,进入Web的管理界面:
如果要查看其它界面,需要输入管理员密码,比如查看存储的界面:
如果要进行创建数据库用户,建表等操作,还得启动sql plus 程序,不用做额外的配置,可以直接启动,这相比收费版,又简单了不少:
具体创建用户,创建表的工作,可以使用Oracle的sql语句来做,但我们这里通过另外一个工具来做,还是在之前的Oracle XE 下载页面:
Oracle SQL Developer | ||
Oracle SQL Developer Data Modeler | ||
Oracle Application Express | ||
针对 Java 开发人员的 JDeveloper | ||
Oracle Developer Tools for Visual Studio .NET | ||
Zend Server |
到这里下载一个最新版本的Oracle VS插件,有好几个版本,下载最上面的就好了,不过下载一样需要Oracle用户账号。
1.2 Oracle VS插件安装使用
安装这个插件的时候,注意安装提示,首先管理员账号Sys和密码,然后是要连接的Oracle服务名,输入相关的服务名,这里默认是 XE,然后保存为一个TNS名字,我用的是mydb,最后还有一个ODP.Net的安装,询问是否安装程序集到GAC,这里选择安装。
安装好后,在VS的“服务器资源管理器”--》“数据连接”,新建一个连接:
在图例中,我们选择以SysDba的角色进行登录,之后,就可以创建用户,查询表和编辑数据了,很方便,这里我建立了一个名字为SOD的用户,然后用这个用户登录:
功能很多,具体内容留给大家去研究了。不过从这里添加的用户不太方便设置成DBA角色,还是用命令行来设置。
至此,Oracle XE 的数据服务和开发工具插件,基本上安装好了。
1.3 PDF.NET集成开发工具连接Oracle
不过,我们也可以使用SOD框架的集成开发工具来连接,该工具连接过程如下:
最后点击确定,回到下面的界面,展开XE数据库,选择数据表,右键菜单查询数据:
至此,Oracle 的安装,连接过程就完成了,很简单。
二、SOD框架的Oracle CodeFirst支持
SOD框架是PDF.NET开发框架的数据框架,目前已经支持了sqlServer,sqlServerCe,Access,MysqL,Postgresql等主流数据库的Code First,但PDF.NET_SOD Ver 5.2.1.0307 还未实现Oracle的Code First支持,主要原因是我对 Oracle 目前使用较少,如果不是SOD会员用户的强烈要求,可能SOD对Oracle Code First支持还要往后推延一段时间。
2.1 Oracle自增列处理
实际上SOD框架对Oracle Code First的支持并不复杂,主要需要解决的问题就是Oracle数据库自增字段的处理,大部分情况下,这都是通过触发器来实现的。
改写下 EntityCommand 类的创建表的方法,添加Oracle的处理:
public string CreateTableCommand { get { if (_createTableCommand == null) { string script = @" CREATE TABLE @TABLENAME( @FIELDS ) "; if (this.currDb.CurrentDBMSType == PWMIS.Common.DBMSType.Postgresql && !string.IsNullOrEmpty(currEntity.IdentityName)) { string seq = "CREATE SEQUENCE " + currEntity.TableName + "_" + currEntity.IdentityName + "_" + "seq INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;"; script = seq + script; } else if (this.currDb.CurrentDBMSType == PWMIS.Common.DBMSType.Oracle && !string.IsNullOrEmpty(currEntity.IdentityName)) { // --; 语句分割符号 string seqTemp = @" CREATE SEQUENCE @TableName_@IDName_SEQ MINVALUE 1 NOMAXVALUE INCREMENT BY 1 START WITH 1 NOCACHE ;-- CREATE OR REPLACE TRIGGER @TableName_INS_TRG BEFORE INSERT ON [@TableName] FOR EACH ROW WHEN(new.[@IDName] IS NULL) BEGIN SELECT @TableName_@IDName_SEQ.NEXTVAL INTO :new.[@IDName] FROM DUAL; END; ;-- "; script = script + ";--\r\n" + seqTemp.Replace("@TableName",currEntity.TableName).Replace("@IDName",currEntity.IdentityName); } var entityFields = EntityFieldsCache.Item(this.currEntity.GetType()); string fieldsText = ""; foreach (string field in this.currEntity.PropertyNames) { string columnScript =entityFields.CreateTableColumnScript(this.currDb as AdoHelper,this.currEntity,field); fieldsText = fieldsText + "," + columnScript+"\r\n"; } string tableName =this.currDb.GetPreparedsql("["+ currTableName+"]"); _createTableCommand = script.Replace("@TABLENAME",tableName).Replace("@FIELDS",fieldsText.Substring(1)); } return _createTableCommand; } }
2.2 SOD Oracle Code First实现过程
由于Oracle 数据库的字段类型名称,对应DbType的名字并不完全相符,所以需要对AdoHelper类的Oracle实现类稍加修改:
public class Oracle : AdoHelper { //其它略 public override string GetNativeDbTypeName(IDataParameter para) { OracleParameter oraPara = (OracleParameter)para; OracleType oraType = oraPara.OracleType; if (oraType == OracleType.DateTime) return "Date"; else if (oraType == OracleType.Int32) return "INT"; else return oraType.ToString(); } }
能够根据实体类,得到生成表的建表脚本,任务已经完成了一半,不过SOD提供了一个DbContext类的封装,可以自动完成这个过程,下面就来实现一个Oracle的DbContext:
namespace PWMIS.Core.Extensions { public abstract class OracleDbContext :DbContext { /// <summary> /// 用连接字符串名字初始化本类 /// </summary> /// <param name="connName"></param> public OracleDbContext(string connName) : base(connName) { } /// <summary> /// 检查实体类对应的数据表是否在数据库中存在 /// </summary> protected override void CheckTableExists<T>() { //创建表 if (CurrentDataBase.CurrentDBMSType == PWMIS.Common.DBMSType.Oracle) { var entity = new T(); var dsScheme = CurrentDataBase.GetSchema("Tables",null); string owner = CurrentDataBase.ConnectionUserID; var rows = dsScheme.Select("OWNER='"+ owner +"' and table_name='" + entity.GetTableName() + "'"); if (rows.Length == 0) { EntityCommand ecmd = new EntityCommand(entity,CurrentDataBase); string sql = ecmd.CreateTableCommand; //OracleClient 不能批量执行多条sql语句 string[] sqlArr = sql.Split(new string[] {";--" },StringSplitOptions.RemoveEmptyEntries); foreach (string item in sqlArr) { if(item.Length >10) //去除回车行 CurrentDataBase.ExecuteNonQuery(item); } } } } } }
2.3 Code First 使用示例
将SOD框架源码的 SampleORMTest 测试项目的LocalDbContext 的代码稍加修改:
namespace SampleORMTest { /// <summary> /// 用来测试的本地sqlServer 数据库上下文类 /// </summary> public class LocalDbContext : DbContext //OracleDbContext, sqlServerDbContext 会根据 local连接字符串自动决定内部使用 { public LocalDbContext() : base("local") { //local 是连接字符串名字 } #region 父类抽象方法的实现 protected override bool CheckAllTableExists() { //创建用户表 CheckTableExists<User>(); return true; } #endregion } }
只需要在OracleDbContext 实现类的CheckAllTableExists 方法内,实现各个实体类的表创建工作即可,比如本例创建用户表。
<connectionStrings> <!--<add name="local" connectionString="Data Source=.;Initial Catalog=LocalDB;Integrated Security=True" providerName="sqlServer" />--> <!--下面的配置适应于 Oracle.Client--> <add name="local" connectionString="Data Source=XE;User Id=SOD;Password=sod123;Integrated Security=no;" providerName="Oracle" /> </connectionStrings>
然后,像下面这样使用,即可自动创建数据库和表,并且添加一条初始数据:
LocalDbContext context = new LocalDbContext();//自动创建表 User zhang_san = new User() { Name = "zhang san",Pwd = "123" }; count += context.Add<User>(zhang_san);//采用 DbContext 方式插入数据
当然插入数据的方式很多,具体请看本文提供的源码下载。
最后,像下面这样使用查询即可:
User user = new User(){ Name="zhang san";}; OQL q=OQL.From(user) .Select() .Where(user.Name) .END; List<User> users = EntityQuery<User>.QueryList(OQL);
这种方式适合简单的相等条件查询,如果需要复杂的条件,可以修改成下面这个样子:
User user = new User(); OQL q = OQL.From(user) .Select() .Where(cmp => cmp.Comparer(user.Name,"=","zhang san") ) .END; List<User> users = EntityQuery<User>.QueryList(q);
示例代码中的 可以修改成 >,<,like 等sql支持的比较符号。
如果需要更多条件,可以使用 &表示sql的AND,| 表示 sql的OR 逻辑关系,比如:
1
2
3
4
5
6
|
User user =
new
User();
OQL q = OQL.From(user)
.Select()
.Where(cmp => cmp.Comparer(user.Name,
"="
,
"zhang san"
) &
cmp.Comparer(user.Pwd,
"123"
) )
.END;
|
这样,一个简单的ORM使用实例就做好了。上面这段ORM例子,不仅仅适用于Oracle,使用在其它数据库都是可以得,只需要修改 连接字符串配置的 providerName和 connectionString 即可,比如 privideName="sqlServer"
三、使用ODP.Net 访问Oracle数据库
3.1 创建SOD的ODP.Net扩展程序集
在本文中,已经说到安装了Oracle 的.net数据访问组件ODP.Net,MS也建议用这个组件来代替MS自己的Oracle.Client,下面,我们只需要新建立一个项目,引用下ODP.Net组件即可:
把SOD框架的核心程序集PWMIS.Core 的Oracle.cs 文件拷贝下来,只需要修改下命名空间即可使用。
编译这个项目,让SampleORMTest 测试项目引用它,或者直接拷贝DLL到测试项目,
3.2 运行32位的ODP.Net
<add name="local" connectionString="Data Source=XE;User Id=SOD;Password=sod123" providerName="PWMIS.DataProvider.Data.OracleDataAccess.Oracle,PWMIS.OracleClient" />
运行项目,首先抛出下面这样一个异常:
其他信息: 未能加载文件或程序集“Oracle.DataAccess,Version=2.121.2.0,Culture=neutral,PublicKeyToken=89b483f429c47342”或它的某一个依赖项。试图加载格式不正确的程序。
第一反应,应该是32位于6位程序不兼容的问题,仔细回想下,这可能是 Oracle VS插件安装时候安装到GAC里面的程序集。于是将测试程序修改成32位的(编译目标为x86),运行良久,再次报错,说TNS无法解析。
奇怪,使用MS Oracle Client都没有问题,为何用了ODP.Net缺不行了呢?百度了下,但觉得别人说的跟我当前不太一样。
检查Oracle的VS插件程序的安装目录,在 E:\app\client\dth\product\12.1.0\client_1\Network\Admin 目录中发现TSN配置文件 tnsnames.ora ,打开,原来是这样的内容:
mydb = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE) ) )
分析内容,这应该是安装VS插件的时候,配置生成的。 那么原来的XE服务的监听名字是怎么来的? 在搜索下Oracle服务的安装目录,在 E:\oraclexe\app\oracle\product\11.2.0\server\network\ADMIN 下面找到了 tnsnames.ora 文件,打开:
XE = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dth-home)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE) ) ) EXTPROC_CONNECTION_DATA = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1)) ) (CONNECT_DATA = (SID = PLSExtProc) (PRESENTATION = RO) ) ) ORACLR_CONNECTION_DATA = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1)) ) (CONNECT_DATA = (SID = CLRExtProc) (PRESENTATION = RO) ) )
原来默认的Oracle XE 监听服务名是这样定义的。
重新配置连接,将服务名从XE更改为mydb,顺利通过。
<add name="local" connectionString="Data Source=mydb;User Id=SOD;Password=sod123" providerName="PWMIS.DataProvider.Data.OracleDataAccess.Oracle,PWMIS.OracleClient" />
如果不配置mydb这个TNS名字,可否直接使用呢?答案是可以,只需要将连接字符串做如下修改即可:
<add name="local" connectionString="Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE) ) );User Id=SOD;Password=sod123" providerName="PWMIS.DataProvider.Data.OracleDataAccess.Oracle,PWMIS.OracleClient" />
测试运行,成功,可惜目前为止,还是基于32位的ODP.Net做的测试。
3.3 64位ODP.Net 使用
回忆之前安装XE数据库服务,确认当时安装的是64位的数据库,那么去它的安装目录,看看有没有ODP,一看,果然有:
E:\oraclexe\app\oracle\product\11.2.0\server\odp.net\bin\2.x
这里的 Oracle.DataAccess.dll 是64位的。
将它拷贝到SOD框架下面,再运行,终于看到了成功界面:
四、免安装Oracle客户端,使用ODP.Net
前面使用ODP.Net的过程,都是在本地机器安装了Oracle XE数据库和Oracle VS 开发插件的情况下进行的,但是,如果把访问Oracle的程序部署到一台没有装过Oracle程序的机器上,程序是无法使用的,这还得做下Oracle 环境的部署,过程如下:
4.1,下载ODAC
打开下面的链接:
http://www.oracle.com/technetwork/topics/dotnet/downloads/index-2235287.html?ssSourceSiteId=otncn