最近在做的Ruby on Rails项目中,需要将远程数据库中的数据对接到项目数据库中,但是远程的数据不仅数据表名跟字段命名奇葩,数据结构本身跟项目数据结构出入比较大,在数据导入过程中代码经历了几次重构,最后使用了YAML文件解决了基本数据1对接的问题。在此写一篇博文,我会尽量重现一路过来的代码变更,算是分享一下我的思考过程,也算是祭奠一下自己的苦逼岁月。
假设以及数据结构预览
因为远程数据库服务器为Oracle Server,我在项目中使用到了Sequel这个gem用于连接数据库以及数据查询,因为数据库连接的内容不是本文的重点,故后续代码直接用remote_database
表示数据库连接,而根据Sequel的用法,我们可以直接使用remote_database[table_name]
连接到具体的表。
本次需要从远程数据库中导入的基本数据主要有学生信息表(包含班级名称)、老师信息表以及专业信息表,相应地,项目中(以下称为“本地”)也已经创建好了对应的model。其中学生信息表的表名以及部分数据字段的从本地到远程的映射关系如表所示:
表名或字段名 | 本地 | 远程 |
---|---|---|
表名 | students | XSJBXX |
姓名 | name | XM |
学号 | number | XH |
年级 | grade | NJ |
班级 | belongs_to :klass ??? | BJMC(班级名称) |
老师信息表的表名以及部分数据字段的映射关系为:
表名或字段名 | 本地 | 远程 |
---|---|---|
表名 | teachers | JZGJBXX |
姓名 | name | XM |
职称 | title | ZC |
证件号码 | id_number | ZJHM |
数据对接第一版:属性方法显式赋值
第一个导入的数据表是学生的信息表,在最开始的时候,因为只需要考虑一张单独的表,所以代码写得简单粗暴,基本过程就是:根据需要的信息,查询对应的远程数据字段,然后使用属性方法赋值,最后保存接入的数据。对接方法的部分相关代码示例(为了方便阅读以及保护项目敏感信息,本文对项目中原有代码进行了缩减以及修改):
# app/models/student.rb
class Student < ActiveRecord::Base
def import_data_from_remote
remote_students = remote_database[:xsjbxx].page(page)
remote_students.each do |remote_student|
name, number, grade = *remote_student.values_at(:xm, :xh, :nj)
class_name = remote_student[:bjmc]
klass = Klass.find_or_create_by name: class_name
student = Student.find_or_create_by name: name,
number: number,
grade: grade,
klass: klass
end
end
end
上面的代码,呃,中规中矩,基本体现了各取所需的指导思想,但是总觉得怎么有点不好呢?
数据对接第二版:通过本地到远程数据库字段映射关系自动匹配赋值
在第一版的代码中,最大的坏味道在于:代码中需要把所有需要对接的字段列举出来,一旦遇到字段增删修改的情况,就需要同时更新原来的逻辑代码,太不灵活了,而且列举所有字段本身就是一件非常繁琐枯燥的事情。再