项目中需要将系统从SQLServer数据库迁移到Oracle上。由于原大部分数据访问操作都是通过包装了Entity Framework的统一访问入口实现的,所以需要研究Entity Framework从SQLServer转移到Oracle的实现方式。

自从EF4.X起,Oracle就为EF提供了驱动支持,但是很可惜的是不支持CodeFirst模式。庆幸的是从ODP.NET 11.2.0.3.0开始,Oracle官方提供了支持CodeFirst的纯托管代码的EF驱动。但是有以下几点是需要知道的;

  1. ODP.NET for .NET Framework 4.0支持Entity Framework和LINQ to Entities,但ODP.NET for .NET Framework 2.0并不支持。
  2. Code First的特性只能在Entity Framework 6 以上的版本才能使用。
  3. ODP.NET和Entity Framework支持标量参数绑定。Entity Framework支持通过名称的参数绑定,不支持通过位置的参数绑定。
  4. 只支持访问Oracle 10g release2及以后版本
  5. 使用可升级和分布式事务需要Oracle Service for Microsoft Transaction Server 12.1。ODP.NET在分布式事务中只支持读级别的隔离。

如何使用CodeFirst

接下来才是我们真正需要关心的,如何在项目中使用CodeFirst(本篇默认你已经了解CodeFirst的概念和使用方法)。

有两种方式能找到我们需要的dll:通过Oracle官网下载(在\odp.net4\odp.net\managed\common中),通过NuGet安装。这里我推荐使用NuGet安装。在程序包管理控制台输入:

 
install-package Oracle.ManagedDataAccess.EntityFramework

修改app.config配置如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false"/>
</configSections>
<connectionStrings>
<add name="SampleDataSource" providerName="Oracle.ManagedDataAccess.Client"
connectionString="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=**SERVICE_NAME**)));Persist Security Info=True;User ID=**User ID**;Password=**Password**"/>
</connectionStrings>
<entityFramework>
<defaultConnectionFactory
type="Oracle.ManagedDataAccess.EntityFramework.OracleConnectionFactory, Oracle.ManagedDataAccess.EntityFramework, Version=6.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
<providers>
<provider invariantName="Oracle.ManagedDataAccess.Client"
type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</providers>
</entityFramework>
<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>
</configuration>

定义一个实体对象:

 
    public class SomeInfo
{
public Guid Id { get; set; }
public DateTime DateTimeField { get; set; }
public bool BooleanField { get; set; }
public decimal DecimalField { get; set; }
public int IntField { get; set; }
public string StringField { get; set; }
}

定义数据上下文:

    public class TestDbContext : DbContext
{
public TestDbContext()
: base("name=SampleDataSource")
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TestDbContext>());
} public DbSet<SomeInfo> SomeInfos { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//这里需要指定schema,默认是sqlserver的dbo
modelBuilder.HasDefaultSchema("YOURSCHEMA");
base.OnModelCreating(modelBuilder);
}
}

在确保连接字符串是正确的情况下就可以写一段测试代码来验证了。验证的代码这里就不介绍了。

.NET类型到Oracle类型的映射

由于Oracle和SQLServer的数据类型有些不同所以这里需要介绍下.NET的数据类型和Oracle数据类型的映射。

.NET数据类型 Oracle数据类型 映射方法
Boolean number(1, 0) 使用EDM映射,注意:需要使用EDM映射配置,参考附加信息文档EDM映射节 。
Byte number(3, 0) 使用EDM映射,注意:需要使用EDM映射配置,参考附加信息文档EDM映射节 。
Byte[] blob 默认
Int16 number(5, 0) 默认,注意:需要使用EDM映射配置,参考附加信息文档EDM映射节 。
Int32 number(10, 0) 默认,注意:需要使用EDM映射配置,参考附加信息文档EDM映射节 。
Int64 number(19, 0) 默认,注意:需要使用EDM映射配置,参考附加信息文档EDM映射节 。
Decimal number(18, 2) 默认
Single binary_float 默认
Double binary_double 默认
Guid raw(16) 默认
DateTime date 默认
DateTimeOffset timestamp withtime zone 默认
String nclob 默认
String clob 使用IsUnicode() fluent API设置Unicode为false
String nvarchar2 使用HasMaxLength() fluent API或MaxLength标记设置MaxLength不大于2000
String varchar2 使用HasMaxLength() fluent API或MaxLength标记设置MaxLength不大于4000,使用IsUnicode() fluent API设置Unicode为false
String nchar 使用HasMaxLength() fluent API或MaxLength标记设置MaxLength不大于1000,使用HasColumnType() fluent API或Column标记设置Column Type为NCHAR
String char 使用HasMaxLength() fluent API或MaxLength标记设置MaxLength不大于2000,使用HasColumnType() fluent API或Column标记设置Column Type为NCHAR
String Long 使用HasColumnType() fluent API或Column标记设置Column Type为LONG,注意: 不推荐使用Long数据类型。
String rowid 使用HasColumnType() fluent API或Column标记设置Column Type为ROWID
String urowid 使用HasColumnType() fluent API或Column标记设置Column Type为UROWID

注意:

基于字符的列,即:CHAR,NCHAR,VARCHAR2,NVARCHAR2可以存储指定(MaxLength)的字符。但是受限于Oracle的设计,这些列只能存储最多4000 byte。存储的数据和数据库字符集的设定会使有些字符可能需要多个byte,所以尽管这些类型的列被配置为4000(MaxLength)但是可能存储不了这么多字符。如果待存储的数据超过4000byte可以使用CLOB或NCLOB类型的列。

Oracle数据类型的特性配置

接下来的表格里将列出Oracle所支持的Data Annotation和Fluent API:

Data Annotation Fluent API 目的 应用于
Key HasKey 设置主键. All Scalar Types
Required IsRequired 设置列为NOT NULL. All
MaxLength HasMaxLength 设置列最大长度 String
NotMapped Ignore 无需映射该属性 All
ConcurrencyCheck IsConcurrencyToken 该列需要被用作为乐观并发检查

注意:不要使用无长度上限的string属性,因为这会被映射为LOB类型。使用LOB类型的列最为并发检查会导致ORA-00932: inconsistent datatypes error.错误。

All
TimeStamp IsRowVersion 并发控制字段 Not Supported
Column HasColumnType 指定对应数据库数据列类型。

注意:必须是合法的兼容类型。例如一个Date属性是不能映射到number列的。

All
N/A IsUnicode 表示映射到一个N-type类型(nvarchar2或nclob),默认为true。 String
N/A HasPrecision 表示设置decimal的精度。 Decimal

Code First数据迁移

数据迁移的方式和使用SQLServer是一致的,但是需要注意以下两点:

  1. 唯一能自定义的是更改表的user schema
  2. Code First自动迁移只能使用dbo schema。所以需要显示的使用Add-Migration命令进行基于代码的数据迁移。

Code First数据库初始化

ODP.NET支持一下几种数据库初始化方式:

  • CreateDatabaseIfNotExists (默认)
  • DropCreateDatabaseAlways
  • DropCreateDatabaseIfModelChanges
  • NullDatabaseInitializer
  • MigrateDatabaseToLatestVersion

由于Oracle和SQL Server对数据库(database)的定义不同,数据库初始化动作作用于模型中所有Oracle对象。Oracle数据库没有新建或删除,而构成该模型的对象被认为是对数据库的一种操作。

Oracle数据库对象创建

为了支持客户端应用程序,ODP.NET创建和维护所需的数据库对象。下面列举了provider提供的可创建和维护的数据库对象:

  • Table
  • Table Column
  • Primary Key
  • Foreign Key
  • Index
  • Sequence
  • Trigger

注意:

Sequence和Trigger在Oracle 11g R2之后的版本中创建,早期版本的数据库支持标识列。

直接和客户端相关的对象,即:一个表对应一个类,一个列对应一个属性,这些对象的命名都是由客户端提供的,对象的命名必须满足Oracle数据库中对对象标识长度的限制。如果类名的长度超长了,那么在创建这个对象时就会报ORA-00972: identifier is too long的异常。

对于剩余的对象,如果提供的命名长度大于数据库标识长度显示,那么ODP.NET回利用命名生成算法。如果提供的命名未超长那就直接使用。在所有情况下,对象名称会被创建为带引号的标识符一方面是为了保持大小写,另一方面任何特殊字符都可以作为标识符的一部分。

命名算法会按照下面两种方式工作:

  • 从头开始截取原始名称中的一段
  • 从原名称计算出一个数字后缀

下面例子演示一个类对象名称是如何被截取的:

 
public class LongSamplePocoTestClassName
{
[Key]
public int Id { get; set; } [MaxLength()]
public string Name { get; set; }
}

默认生成的主键名称为:

PK_LongSamplePocoTestClassNames

这个名称包含31(最多支持30个字符)个字符,超出了限制。将对其做截取操作,最后生成:

PK_LongSamplePocoTes_730795129

算法被设计为尽可能的保留更多的原始名称。

原创文章,转载请注明: 转载自xdlysk的博客

本文链接地址: 在Oracle中使用Entity Framework 6 CodeFirst

在Oracle中使用Entity Framework 6 CodeFirst的更多相关文章

  1. Oracle中使用Entity Framework 6.x Code-First

    Oracle中使用Entity Framework 6.x Code-First方式开发 去年写过一篇EF的简单学习笔记,当时EF还不支持Oracle的Code-First开发模式,今天无意又看了下O ...

  2. Oracle中使用Entity Framework 6.x Code-First方式开发

    去年写过一篇EF的简单学习笔记,当时EF还不支持Oracle的Code-First开发模式,今天无意又看了下Oracle官网,发现EF6.X已经支持了,并且给出了二篇教程(英文版): 1.Using ...

  3. 如何使用ASP.NET Web API OData在Oracle中使用Entity Framework 6.x Code-First方式开发 OData V4 Service

    环境: Visual Studio 2013 + .Net Framework 4.5.2 1.新建项目 2.安装OData,ODP.NET 安装的包: 下面是部分代码: using System; ...

  4. Asp.net Core中使用Entity Framework Core CodeFirst

    1.安装对应的包 "Microsoft.EntityFrameworkCore.Design": "1.1.0", "Microsoft.Entity ...

  5. MVC中使用Entity Framework 基于方法的查询学习笔记 (一)

    EF中基于方法的查询方式不同于LINQ和以往的ADO.NET,正因为如此,有必要深入学习一下啦.闲话不多说,现在开始一个MVC项目,在项目中临床学习. 创建MVC项目 1.“文件”--“新建项目”-- ...

  6. Oracle官方版Entity Framework

    千呼萬喚始出來! Oracle官方版Entity Framework問市,邁入開發新時代 自從我得了一種"不用LINQ就不會寫資料庫程式"的病,為了滿足工作上要搭配Oracle(雖 ...

  7. 如何在ASP.NET Core中应用Entity Framework

    注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...

  8. [转]Using Entity Framework (EF) Code-First Migrations in nopCommerce for Fast Customizations

    本文转自:https://www.pronopcommerce.com/using-entity-framework-ef-code-first-migrations-in-nopcommerce-f ...

  9. dotnet ef执行报错, VS 2019发布时配置项中的Entity Framework迁移项显示不出来

    VS 2019发布时配置项中的Entity Framework迁移项显示不出来 dotnet ef dbcontext list --json “无法执行,因为找不到指定的命令或文件.可能的原因包括: ...

随机推荐

  1. Uva 242 邮票和信封

    题目链接:https://vjudge.net/contest/146179#problem/D 题意: 信封上最多贴S张邮票.有N个邮票集合,每个集合有不同的面值.问哪个集合的最大连续邮资最大,输出 ...

  2. apache代理服务器为nodejs服务设置域名

    本机以apache为主,其中 在httpd.conf中先设置 <VirtualHost *:80> ServerName nodejs.cc ServerAlias www.nodejs. ...

  3. Netsuite > Foreign Currency Revaluation 外币评估

    MENU: Transactions > Financial > Revalue Open Currency Balances 使用频率: - 每个月月底,结账前, 手工操作. - 或者在 ...

  4. 【状压DP】bzoj1087 互不侵犯king

    一.题目 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上.下.左.右,以及左上.左下.右上.右下八个方向上附近的各一个格子,共8个格子. I ...

  5. 几个简单的css样式使用说明

    假设我们的单标签是一个 div: 定义如下通用CSS: div{ position:relative; width:200px; height:60px; background:#ddd; } 法一: ...

  6. 28-React state提升、组件组合或继承

    Lifting State Up state提升 对于在React应用程序中更改的任何数据,应该有一个单一的数据源.通常,都是将state添加到需要渲染的组件.如果其他组件也需要它,您可以将其提升到最 ...

  7. 全面分析 Spring 的编程式事务管理及声明式事务管理

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  8. CentOS搭建NodeJS环境

    事件驱动,承受高并发……这些耀眼的光环,使前端开发者不能不去学习NodeJS. 今天就在开发环境把NodeJS搭建起来了. 1. 下载node wget http://nodejs.org/dist/ ...

  9. centos7 docker zookeeper

    docker run --name=zookeepertmp -i -t centos7/jdk7 /bin/bash cd /home wget http://apache.fayea.com/zo ...

  10. caffe安装:ubuntu16.04 + opencv2.4 + python 2.7+ CUDA 8.0 RC + CuDNN 5.0

    官方教程:http://caffe.berkeleyvision.org/install_apt.html 主要参考教程: https://github.com/BVLC/caffe/wiki/Ubu ...