在.NET开发面向Oracle数据库的应用程序

其实这个不是一个什么新的话题。但是之前在多次项目中,总是遇到大家针对Oracle数据库的访问时,会有各种各样的问题,最基本的就是要在客户端安装各种client,版本不一样的话还有各种问题。

静下心来看看,其实也没有那么难。我这里总结一下,如何在.NET应用程序中,简单优雅地使用Oracle数据库。

第一个原则:不要依赖

最好的情况就是,程序自己就可以完成数据访问,不需要额外地安装所谓的Oracle Client,那是一个很麻烦而且痛苦的事情。

我们首先看看,如果不装任何东西,是否可以实现Oracle数据库访问?

其实,.NET本身是自带了针对Oracle数据库访问的组件的,就是下面这个System.Data.OracleClient

在.NET开发面向Oracle数据库的应用程序

我们的代码如下(这是最原始的ADO.NET代码,只是做演示)

using System;
using System.Data.OracleClient;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var connectionString = "user id=system;password=password;data source=192.168.56.101:1521/orcl";

using (var connection = new OracleConnection(connectionString))
            {
                var cmd = connection.CreateCommand();
                cmd.CommandText = "select * from sys.dba_all_tables";
                connection.Open();
                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine(reader.GetString(0));

}

reader.Close();
                connection.Close();

}
           
        }
    }
}

看起来应该是没有问题的,运行起来却会报错

Additional information: System.Data.OracleClient requires Oracle client software version 8.1.7 or greater.

在.NET开发面向Oracle数据库的应用程序

这里的提示就是说,需要有Oracle Client。

这不是我们希望看到的结果。实际上原理上说,我们这么理解吧,可能是这个组件只是一个wrapper,它实际去操作数据库,还需要通过Oracle Client才能实现。

使用Oracle提供的组件

更好的建议就是,使用Oracle 官方提供的托管代码组件。Oracle.ManagedDataAccess.dll

在.NET开发面向Oracle数据库的应用程序

在.NET开发面向Oracle数据库的应用程序

只要添加了这个Nuget Package,代码几乎不需要任何改动,直接就可以复用。

using System;
using Oracle.ManagedDataAccess.Client;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var connectionString = "user id=system;password=password;data source=192.168.56.101:1521/orcl";

using (var connection = new OracleConnection(connectionString))
            {
                var cmd = connection.CreateCommand();
                cmd.CommandText = "select * from sys.dba_all_tables";
                connection.Open();
                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine(reader.GetString(0));

}

reader.Close();
                connection.Close();

}
           
        }
    }
}

当然比较理想的情况是将连接字符串之类的,可以放在配置文件中去。这个很简单,这里就不说明了。

结合Entity Framework使用

Entity Framework 出来已经好多年了,几乎成了所有.NET应用程序中的标配(不管有没有用到)。现在的最新版本应该是 6.1.3 .同时,需要注意的是,以后会有一个所谓的Entity Framework Core ,而且开源了 https://github.com/aspnet/EntityFramework

回到正题,之前的代码写法其实还是比较原始的,那么如何结合Entity Framework进行Oracle数据库方面的编程呢?

首先,安装下面的这个组件:Oracle.ManagedDataAccess.EntityFramework

在.NET开发面向Oracle数据库的应用程序

然后,可以使用Code first的方式编写如下代码

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

namespace ConsoleApplication
{
    public class OracleContext : DbContext
    {
        public OracleContext() : base("OracleDbContext")
        {

}

public DbSet<Employee> Employees { get; set; }

}

[Table("EMPLOYEES", Schema = "SYSTEM")]
    public class Employee
    {
        [Key()]
        [Column("EMPLOYEEID")]
        public int EmployeeID { get; set; }

[Column("FIRSTNAME")]
        public string FirstName { get; set; }
        [Column("LASTNAME")]
        public string LastName { get; set; }
    }
}

这里的代码没有什么出奇的。配置文件需要有如下的设置(一般在添加Oracle.ManagedDataAccess.EntityFramework 这个组件的时候,会自动修改配置文件)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="oracle.manageddataaccess.client" type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <oracle.manageddataaccess.client>
    <version number="*">
      <dataSources>
        <dataSource alias="oracle" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.101)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) " />
             </dataSources>
    </version>
  </oracle.manageddataaccess.client>
  <connectionStrings>
    <add name="OracleDbContext" connectionString="user id=system;password=password;data source=oracle" providerName="Oracle.ManagedDataAccess.Client" />
  </connectionStrings>
  <system.data>
    <DbProviderFactories>
      <remove invariant="Oracle.ManagedDataAccess.Client" />
      <add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver" type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
    </DbProviderFactories>
  </system.data>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <publisherPolicy apply="no" />
        <assemblyIdentity name="Oracle.ManagedDataAccess" publicKeyToken="89b483f429c47342" culture="neutral" />
        <bindingRedirect oldVersion="4.121.0.0 - 4.65535.65535.65535" newVersion="4.121.2.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v13.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="Oracle.ManagedDataAccess.Client" type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

后台数据库的表格设计也是很简单。

在.NET开发面向Oracle数据库的应用程序

需要注意的是,经过实验,我发现目前这个Entity Framework要求所操作的表必须要有主键,而且主键必须是一个identity column(即自己绑定一个序列,实现自动增长),否则会报错

实际上后台会通过一个触发器来实现这个功能

create or replace TRIGGER EMPLOYEES_TRG
BEFORE INSERT ON EMPLOYEES
FOR EACH ROW
BEGIN
  <<COLUMN_SEQUENCES>>
  BEGIN
    IF INSERTING AND :NEW.EMPLOYEEID IS NULL THEN
      SELECT EMPLOYEES_SEQ.NEXTVAL INTO :NEW.EMPLOYEEID FROM SYS.DUAL;
    END IF;
  END COLUMN_SEQUENCES;
END;

接下来在前端程序中就简单多了,下面是一个代码片段

var ctx = new OracleContext();

ctx.Employees.Add(new Employee() {FirstName = "ares", LastName = "chen" });
ctx.SaveChanges();

var query = ctx.Employees.ToArray();
foreach (var item in query)
{
    Console.WriteLine(item);
}

需要注意的是,如果需要使用Entity Frmaework的Database first或Model first的功能,还是需要安装Oracle Client,或者准确地说应该是ODAC组件

http://www.oracle.com/technetwork/developer-tools/visual-studio/downloads/index.html

上一篇:MySQL5.6 replication architecture --原图来自姜承尧


下一篇:SQL*Loader FAQ