ABP框架的数据访问底层是基于EFCore(Entity Framework Core)的,是微软标志性且成熟的ORM,因此它本身是支持多种主流数据库MySQL,SqlServer,Oracle,SQLite等等的,我在上篇随笔《ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据》已经详细介绍过如何从SQLServer迁移支持Mysql数据库的操作,同时介绍如何从SQLServer基础数据,通过Navicat工具,实现数据库迁移到Mysql上去。本篇随笔继续介绍ABP框架实现Oracle的适配和数据库的迁移处理。

1、ABP框架中Oracle数据库的适配处理

ABP框架底层是使用EFCore来实现数据处理的,框架默认是使用SQLServer数据库的,如果需要切换到Oracle数据库上去,使用EF Core操作Oracle数据库,首先需要安装Oracle.EntityFrameworkCore,可以直接在NuGet上直接搜索安装即可。

首先在ABP框架的EntityFrameworkCore项目右键上选择【管理NuGet程序包】,然后 搜索Oracle,选择Oracle.ManagedDataAccess.Core和Oracle.EntityFrameworkCore即可,如下所示。

Oracle.ManagedDataAccess.Core是基于ODP的.netcore的驱动程序,是我们访问Oracle的时候,摆脱X86,X64的繁琐限制。

这个Oracle的ODP.NET方式,之前在微软企业库的相关框架就已经用过,非常不错,有兴趣可以参考随笔《在开发框架中扩展微软企业库,支持使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库》了解一下。

它的连接字符串类似下面的格式

<add name="oracle3" providerName="OracleManaged"  connectionString="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)));User ID=win;Password=win" />

如果是我们目前ABP框架,这是采用appSetting.json的方式了,格式如下所示。

  "ConnectionStrings": {
"Default": "Server=.\\SQL2014; Database=MyProjectDb; Trusted_Connection=True;",
"Oracle": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)));User ID=C##ABP;Password=abp",
"MySql": "Server=localhost;Database=myprojectdb;Uid=root;Pwd=123456;",
"PostgreSQL": "Server=localhost;Port=5432;Database=myprojectdb;User Id=postgres;Password=123456"
},

安装了Oracle的两个驱动文件,我们就需要调整一下对应的代码了,参考随笔《ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据》的处理,我们调整非常方便。

支持,我们感觉好像Oracle的应该调整的差不多了,尝试把项目编译运行,会发现有错误出现:ORA-00942: 表或视图不存在

这个问题开始挺困惑的,而且ABP框架切换到Oracle的相关文章介绍也很少,网上很多做法后来回想起来,他们处理都是不太正确的,至少对于当前EFCore的处理来说,不是正确的。

要了解这个问题:ORA-00942: 表或视图不存在,我们需要来看看EFCore底层对表名和字段的限定符处理逻辑了,我们查看host启动项目的错误日志,得到如下提示。

ERROR 2021-08-15 16:12:46,603 [1    ] oft.EntityFrameworkCore.Database.Command - Failed executing DbCommand (114ms) [Parameters=[], CommandType='Text', CommandTimeout='0']
SELECT "a"."Id", "a"."CreationTime", "a"."CreatorUserId", "a"."DeleterUserId", "a"."DeletionTime", "a"."Discriminator", "a"."DisplayName", "a"."IsDeleted", "a"."LastModificationTime", "a"."LastModifierUserId", "a"."Name", "a"."AnnualPrice", "a"."DailyPrice", "a"."ExpiringEditionId", "a"."MonthlyPrice", "a"."TrialDayCount", "a"."WaitingDayAfterExpire", "a"."WeeklyPrice"
FROM "AbpEditions" "a"
WHERE "a"."Name" = N'Standard'

FETCH FIRST 1 ROWS ONLY

我们可以看到生成的访问SQL,它使用了双引号作为限定符。

生成的Sql中是将所有的表名和字段名都用双引号修饰的,而Oracle中存储字段名默认都是采用全大写的形式的,它们是不对应的,使用双引号的对象名称,是大小写敏感的,如下在PLSQL中执行语句。

而不使用限定符的字符串对象,默认是按大写方式来处理的,如下结果所示。

所以如果我们不想将实体类所有的属性名称写成大写,就需要显式的指定映射的column的名称。可以使用DataAnnotations的特性标注所有属性,或者在Context中指定列映射。

显示指定每个访问类的处理方式如下所示。

[Table("EMPLOYEE ")]  //指定数据库对应表名
public class Employee
{
[Key] //主键
[Column("ID")] //指定数据库对应表主键名称
public long Id { get; set; } [Column("EMPLOYEENO")]
public int EmployeeNo { get; set; } [Column("NAME")]
public string Name { get; set; } [Column("BIRTHDAY")]
public DateTime BirthDay { get; set; } [Column("DEPARTMENT")]
public string Department { get; set; } [Column("ISVALID")]
public bool IsValid { get; set; }
}

这种方式肯定不是很好的方法,这种方式处理起来很累赘,而且ABP框架很多基类我们是通过官方DLL来引用的,没有或者很麻烦去修改相关的映射关系。

那么我们考虑动态公共映射的方式处理,尽量避免这种劳而无功的方式。

我们知道ABP框架中的EntityFrameworkCore项目里面,我们可以通过代码的方式修改它们和表、字段的映射关系,我们的规则就是让它(表名、字段名)变为大写,这样即使它们使用了限定符,也不改变SQL的处理结果。

我们修改EF模型OnModelCreating的处理逻辑,如下代码所示,红框部分就是我们改变问题所在的核心。

运行Host启动项目,我们发现后端的Swagger能够正常打开,成功了第一步了。

2、使用Oracle的序列和触发器解决自增ID的问题

不过登陆进入的时候,会发现出现 违反唯一约束条件的错误,这个是由于登录的时候,无法写入日志,因为无法让这个表的自增ID为NULL,违反了数据约束规则。

到这里,我们Oracle方面基本上就解决了大问题了,不过就是还有一个自增长的问题。

INSERT INTO "C##ABP"."ABPUSERTOKENS" ("EXPIREDATE", "LOGINPROVIDER", "NAME", "TENANTID", "USERID", "VALUE")
VALUES (:p0, :p1, :p2, :p3, :p4, :p5)
RETURNING "ID" INTO "lABPUSERTOKENS_0"(1)."ID";
OPEN :cur1 FOR SELECT "lABPUSERTOKENS_0"(1)."ID" FROM DUAL;
END;
ERROR 2021-08-14 17:27:18,636 [52 ] osoft.EntityFrameworkCore.Infrastructure - 2021-08-14 17:27:18.636902 ThreadID:52 (ERROR) OracleExecutionStrategy.ExecuteAsync() : Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-00001: 违反唯一约束条件 (C##ABP.PK_ABPUSERTOKENS)
ORA-06512: 在 line 13

Oracle插入数据倒是和其他数据库差别不大,但是由于Oracle天生是没有自增Id的,如果我们设计的表的主键需要采用自增键就需要使用Sequence序列代替,通过序列和触发器的方式结合,我们可以顺利解决自增长的问题。

我们一般通过序列和触发器的结合,自动为自增长ID写入对应的起步值,定义Oracle序列和触发器的代码如下所示。

--表 WEB_SITEARTICLE 的自增序列和触发器
CREATE SEQUENCE WEB_SITEARTICLE_ID_AUTO
MINVALUE 1 --定义序列的初始值(即产生的第一个值),默认为1。
MAXVALUE 99999999999
START WITH 70 --因为表中已有3条数据,所以要从第4开始,如果尚未插入数据,那写1即可。
INCREMENT BY 1 --用于定义序列的步长,如果省略,则默认为1,如果出现负值,则代表序列的值是按照此步长递减的。
NOCYCLE --CYCLE代表循环,NOCYCLE代表不循环。
NOCACHE; --CACHE建立缓冲区,NOCACHE不建缓冲区 CREATE OR REPLACE TRIGGER WEB_SITEARTICLE_ID_TRIGGER
BEFORE INSERT ON WEB_SITEARTICLE --before:表示在数据库动作之前触发器执行; after:表示在数据库动作之后触发器执行。
FOR EACH ROW --对表的每一行触发器执行一次。如果不写,则只对整个表执行一次。
BEGIN
SELECT WEB_SITEARTICLE_ID_AUTO.NEXTVAL INTO :NEW.ID FROM DUAL; -- :new 为一个引用最新的列值;:old 为一个引用以前的列值; 这两个变量只有在使用了关键字 "FOR EACH ROW"时才存在.且update语句两个都有,而insert只有:new ,delect 只有:old;
END WEB_SITEARTICLE_ID_TRIGGER;

下面就是我们实际的文件中,为ABP框架的Oracle表创建序列和触发器的SQL代码截图。

执行后,我们就可以通过PLSQL查看到对应的序列和触发器列表,并可以进行适当的调整了。

序列如下:

触发器列表如下所示。

弄完这些,如果我们的Oracle表和数据都准备好了,那么就没有什么问题了,已经可以正常使用ABP框架在Oracle上跑了。

由于我们之前已经通过Navicat的方式迁移传输了SQLserver的数据,我们可以顺利跑起来ABP框架了,整套框架包括了WebAPI后端的Swagger管理、Vue&Element的管理前端、Winform管理前端,以及公司门户网站几个部分。

ABP 框架Swagger接口端

ABP框架之Vue&Element端

ABP框架之Winform端 

ABP框架之公司门户网站

 

3、SQLServer结构和数据迁移到Oracle

我在上篇随笔《ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据》也详细介绍过使用Navicat工具实现SQLserver 数据库迁移到Mysql的处理方式,这里依旧使用这个方式,实现SQLserver 数据库迁移到Oracle。

首先我们需要创建对应的Oracle用户和表空间,用来承载表的结构和数据的存储。如果我们是基于Oracle的DMP导出文件,那么可以不用提前创建用户和表控件也行。

注意,由于ABP框架使用的数据库表和键名称等的标识超过了30个字符,而Oracle12c以下版本不支持超过30个字符的标识,因此本ABP项目以Oracle12c起步的数据库,用于解决这个标识问题。

由于Oracle12C的创建全局用户,需要以C##开始,因此创建用户的代码和Oracle11的有所差异。

下面是基于Oracle12C的创建用户和表空间SQL代码。用户名为C##ABP,密码为abp

create tablespace abp_tbs datafile 'C:\app\Administrator\virtual\oradata\orcl\whcdb\abp_tbs.dbf' size 100M;
--DROP TABLESPACE abp_tbs INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS;
create user C##ABP identified by abp default tablespace abp_tbs; grant connect,resource to C##ABP;
grant dba to C##ABP;
--Revoke dba from C##ABP;

弄完这些准备工作,就到Navicat工具出场了。

通过数据传输的方式,我们构建Oracle数据的处理,分别设置源和目标的配置。

并注意通过选项的方式,设置好传输的规则。

其中我们需要设置让标识转换为大写,这个符合Oracle的处理规则,否则用了双引号的标识符,就不正确了。

另外遇到错误继续,是因为Oracle 的迁移,有些记录无法顺利处理,我们可以通过手工的方式补齐它,特别是NCLOB的内容,有些限制。

选定好相关的表内容,就可以继续一步步完成即可创建和导出表数据了。

最后我们通过PLSQL查看相关的表内容如下所示。

到这里,切换Oracle的后端代码,以及数据库的数据,包括创建对应自增记录字段ID的序列和触发器的处理也完成了,这样就可以顺利完成整个Oracle的迁移和处理了。

ABP框架使用Oracle数据库,并实现从SQLServer中进行数据迁移的处理的更多相关文章

  1. ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据

    ABP默认的数据库是SQLServer,不过ABP框架底层是EF框架,因此也是很容易支持其他类型的数据库的,本篇随笔介绍在ABP框架使用Mysql数据库,以及基于SQLServer创建MySql数据库 ...

  2. Oracle数据库date类型与Java中Date的联系与转化

    以下是对Java中的日期对象与Oracle中的日期之间的区别与联系做点说明,以期对大家有所帮助.new Date():分配 Date 对象并初始化此对象,以表示分配它的时间(精确到毫秒),就是系统当前 ...

  3. 把数据库里面的stu表中的数据,导出到excel中

    # 2.写代码实现,把我的数据库里面的stu表中的数据,导出到excel中 #编号 名字 性别 # 需求分析:# 1.连接好数据库,写好SQL,查到数据 [[1,'name1','男'],[1,'na ...

  4. ABP框架连接Mysql数据库

    开始想用Abp框架来搭建公司的新项目,虽然一切还没有定数,但是兵马未动,粮草先行,我先尝试一下整个过程,才能够更好的去争取机会. 此次技术选型:Abp(Asp.Net core mvc)+mysql( ...

  5. 用JDBC访问ORACLE数据库 关于commit 增快效率 大数据 等的整理

    1.问:用JDBC访问ORACLE数据库,做DELETE操作,能用JAVA多线程实现吗? ORACLE服务器要怎么配?(以下答案来自网络,仅供参考) 答: Oracle有自己的锁机制.就算你开100条 ...

  6. 如何设置Oracle数据库客户端字符集以及系统中的NLS_LANG环境变量

    概述: 本地化是系统或软件运行的语言和文化环境.设置NLS_LANG环境参数是规定Oracle数据库软件本地化行为最简单的方式. NLS_LANG参数不但指定了客户端应用程序和Oracle数据库所使用 ...

  7. Oracle 数据库字典 sys.obj$ 表中关于type#的解释

    sys.obj$ 表是oracle 数据库字典表中的对象基础表,所有对象都在该表中有记录,其中type#字段表明对象类型,比如有一个表 test ,则该对象在sys.obj$ 中存在一条记录,name ...

  8. Oracle中的数据迁移到Mysql数据库中的方式Navicat premium工具

    1.安装 Navicat premium工具 2.破解 Navicat premium工具 3.连接需要相互迁移的两个库Mysql和Oracle(可以是远程的或者本机的数据库都是可以的) 4.连接上之 ...

  9. 简单粗暴将sqlserver表以及数据迁移到oracle

    1.利用sqlserver工具查询出表中所有数据,全选,右键 -连同标题一起复制. 2.将数据保存到excel文件,数据 时间类型(yyyy--MM--dd HH:mm:ss)最好处理一下,需要将id ...

随机推荐

  1. 同步工具——Exchanger

    本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 本文是转载文章,原文请见这里 一.Exchanger简介 ...

  2. hdu 6050 Funny Function 矩阵快速幂

    就算告诉我是矩阵快速幂我也推不出递推式呀!!! 官方题解: 对于任意i>=1,当j>=3时,有通过归纳法可以得到 进而推导出 后来自己重新推导了一遍 #include <iostre ...

  3. CRM系统个性化定制的对企业的优势作用

    伴随着科学技术的不断发展,企业信息化建设也在持续地开展.企业管理模式已经开始由传统模式向信息化转变,并且越来越多的企业开始使用互联网软件来进行辅助管理,这一趋势也让CRM客户管理系统得到快速的发展.市 ...

  4. 重新整理 .net core 实践篇————重定向攻击[三十九]

    前言 简单介绍一下重定向攻击. 正文 攻击思路: 看着上面挺复杂的,其实是一些很简单的步骤. 攻击者通过某些手段,让用户打开了一个好站点,打开的这个地址里面带有重定向信息,重定向信息就是自己伪造的站点 ...

  5. Linux:Linux更新yum方法

    [内容指引]进入目录:cd查看目录下的内容:ls重命名备份:mv从网络下载:wgetyum更新:yum update 第一次运行yum安装软件前,建议更新yum. 1.进入yum源目录 命令: cd ...

  6. Android java层常见加密算法的hook自吐以及栈信息的打印

    杂谈:其实原理并没有很难,本质就是hook Android的框架层中的api将我们想要的key和iv(也可以没有,就打个比方),但是目前的话,很多厂家已经不在直接调用java层的这些加密算法的api了 ...

  7. androidstudio创建第一个so文件

    前言:之前看安卓软件安全与逆向分析这书,看到ndk开发这节,发现自己连so文件都没编译操作过233,所以就直接上手试试, 感觉挺好玩的,把关键的加密流程都放进so中去实现,这周先写个demo试试,感觉 ...

  8. 第12次抽考(GUI)

    1. package week4; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextFiel ...

  9. OpenMVG 系列 (2):Image 和 Numeric

    OpenMVG 的功能模块由若干核心库组成,本文主要介绍 Image 和 Numeric 两个库 1  Image Image 库包含图像容器 Image<T>.图像IO读写函数 Read ...

  10. Nginx的安装和部署

    Nginx简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行.其特点是占有内存少,并发能力强,事实上nginx的并发 ...