在Oracle中使用Entity Framework 6 CodeFirst
项目中需要将系统从SQLServer数据库迁移到Oracle上。由于原大部分数据访问操作都是通过包装了Entity Framework的统一访问入口实现的,所以需要研究Entity Framework从SQLServer转移到Oracle的实现方式。
自从EF4.X起,Oracle就为EF提供了驱动支持,但是很可惜的是不支持CodeFirst模式。庆幸的是从ODP.NET 11.2.0.3.0开始,Oracle官方提供了支持CodeFirst的纯托管代码的EF驱动。但是有以下几点是需要知道的;
- ODP.NET for .NET Framework 4.0支持Entity Framework和LINQ to Entities,但ODP.NET for .NET Framework 2.0并不支持。
- Code First的特性只能在Entity Framework 6 以上的版本才能使用。
- ODP.NET和Entity Framework支持标量参数绑定。Entity Framework支持通过名称的参数绑定,不支持通过位置的参数绑定。
- 只支持访问Oracle 10g release2及以后版本
- 使用可升级和分布式事务需要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是一致的,但是需要注意以下两点:
- 唯一能自定义的是更改表的user schema
- 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.x Code-First
Oracle中使用Entity Framework 6.x Code-First方式开发 去年写过一篇EF的简单学习笔记,当时EF还不支持Oracle的Code-First开发模式,今天无意又看了下O ...
- Oracle中使用Entity Framework 6.x Code-First方式开发
去年写过一篇EF的简单学习笔记,当时EF还不支持Oracle的Code-First开发模式,今天无意又看了下Oracle官网,发现EF6.X已经支持了,并且给出了二篇教程(英文版): 1.Using ...
- 如何使用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; ...
- Asp.net Core中使用Entity Framework Core CodeFirst
1.安装对应的包 "Microsoft.EntityFrameworkCore.Design": "1.1.0", "Microsoft.Entity ...
- MVC中使用Entity Framework 基于方法的查询学习笔记 (一)
EF中基于方法的查询方式不同于LINQ和以往的ADO.NET,正因为如此,有必要深入学习一下啦.闲话不多说,现在开始一个MVC项目,在项目中临床学习. 创建MVC项目 1.“文件”--“新建项目”-- ...
- Oracle官方版Entity Framework
千呼萬喚始出來! Oracle官方版Entity Framework問市,邁入開發新時代 自從我得了一種"不用LINQ就不會寫資料庫程式"的病,為了滿足工作上要搭配Oracle(雖 ...
- 如何在ASP.NET Core中应用Entity Framework
注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...
- [转]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 ...
- dotnet ef执行报错, VS 2019发布时配置项中的Entity Framework迁移项显示不出来
VS 2019发布时配置项中的Entity Framework迁移项显示不出来 dotnet ef dbcontext list --json “无法执行,因为找不到指定的命令或文件.可能的原因包括: ...
随机推荐
- webstorm运行到服务器(Apache)
昨天百度了很多关于webstorm怎么运行到服务器当中的例子,但是我都阅读了一遍,里边貌似没有是关于Apache跟webstorm的配置方式.所以下面是我给大家分享我的亲身体验. 再次强调:这里用的8 ...
- Python 学习随笔1
在一个列表中,找出重复数组的位置. 比如在列表name = [1, 5, 8, 22, 56, 2, 8, 45, 7, 2, 35, 2, 486, 2, 152, 111, 265, 2, 2]中 ...
- EF INNER JOIN,LEFT JOIN,GROUP JOIN
IQueryable<TOuter>的扩展方法中提供了 INNER JOIN,GROUP JOIN但是没有提供LEFT JOIN GROUP JOIN适用于一对多的场景,如果关联的GROU ...
- Netsuite > Foreign Currency Revaluation 外币评估
MENU: Transactions > Financial > Revalue Open Currency Balances 使用频率: - 每个月月底,结账前, 手工操作. - 或者在 ...
- jstl-vaStatus 属性count与index
一个老生常谈的话题,今天有了新得: <% List list= new ArrayList(); list.add("饼干"); list.add("牛奶" ...
- iOS的多版本配置(版本分离,多环境配置)
前几天公司说一个客户要搞一个app,我说搞呗,跟我啥关系...他说,就是从咱的app上搞,什么都一样,就是一些logo啥的不一样.我一开始感觉,那就改改logo呗,后来一想,凑,百度推送,友盟统计,B ...
- node.js + expres 的安装
一 windows下安装 首先去官网下载msi安装包. 两篇很有参考价值的文章: http://cnodejs.org/topic/4fae80c02e8fb5bc650a8360 http://bl ...
- matlab播放音乐
最近在做计算,写了一些matlab代码,脑壳还疼,所以决定发挥一下逗B精神,写一个程序玩一下. 想了想,既然写代码的时候喜欢听歌,而且我的电脑打开网易音乐的速度巨慢(不知道为什么..),那些一个程序直 ...
- Nginx+Tomcat发布时不间断服务的提供
原理 1.使用Nginx反向代理事项负载均衡,至少两个Tomcat(tomcatA+TomcatB)同时提供服务. 2.发布时配置Nginx的nginx.conf,只让其中的TomcatA临时提供所有 ...
- java面向对象设计原则
原则1:DRY(Don't repeat yourself) 即不要写重复的代码,而是用"abstraction"类来抽象公有的东西.如果你需要多次用到一个硬编码值,那么可以设为公 ...