ActiveRecord-连接多张表之单表继承

1. 基本概念

Rails提供了两种机制,可以将复杂的面向对象模型映射为关系模型,即所谓的单表继承(single-table inheritance)和多态关联(polymorphic associations,也有人称为多表继承)。

2. 单表继承

在使用面向对象开发时,经常会用到类和继承,如应用程序中涉及不同角色的人员(People):顾客(Customer)、员工(Employee)和经理(Manager)等等。其中有一些属性是共有的,另一些属性是特有的。因此,创建模型:Customer类和Employee类,且都是People的子类,Manager类是Employee的子类。子类会继承父类的所有属性和行为。

这些都是代码中的模型体现,在关系型数据库是如何体现的?见如下代码:

# model的定义
class People
# 迁移文件的定义,即关系型数据库的体现
create_table :people, :force => true do |t|
t.column :type, :string # common attributes
t.column :name, :string
t.column :email, :string # attributes for type=Customer
t.column :balance, :decimal, :precision => 10, :scale => 2 # attributes for type=Employee
t.column :reports_to, :integer
t.column :dept, :integer # attributes for type=Manager
# none
end
# 添加人员

boss = Manager.create({name: 'Jobs', email: 'jobs@apple.com', dept: 1})

empl = Employee.new({name: 'David', email: 'david@apple.com', dept: 2})
empl.boss = boss
empl.save user = Customer.create({name: 'Jim', email: 'jim@rails.com', balance: 100})

由上面的代码可以看出类定义中使用了继承,而对于不同角色的人员,均保存于people表,对于boss和empl对象,都是没有user的balance属性的,即这两个对象的balance字段都是null,而对于user对象的dept和reports_to字段同样是null,这样就实现了一个单表继承,相比于我们使用各种其它方法会简单很多。但是问题是:

2.1 ActiveRecord如何如此简单的提供了单表继承?

通过迁移文件中可以看到,在people表中添加了type字段。通过上图也可以看到,每条记录的type字段都有值,而且为用户的角色。ActiveRecord是约定好了使用type字段来描述对象所属的类型。

针对此问题,可以详见Martin Fowler在《企业应用架构模式》的介绍。

2.2 如果一个新加入的开发者使用People添加了人员呢?

是的,也许一个新加入项目组的同学使用People添加了人员,即使是测试,也会感觉到代码不是那么严谨,例如:

god = Person.create({name: 'God', email: 'god@god.god'})

发生了什么?God真的是神啊,type为空,所以,我们一定不想在表中见到神,按如下三种方法均可以解决:

  • 在People中实现一个名为abstract_class?的类方法,并使其返回true,这样,就可以达到目的了。不过它带来的问题是:1.ActiveRecord永远不会尝试寻找对应于抽象类的数据库表,这是对我们有利的,2.抽象类的子类会被当作各自独立的ActiveRecord模型类,即各自映射到一张独立的数据库表。这就达不到我们对公共属性抽取的目的了。这种方法不完美
  • 使用Ruby模块来包含这些需要共享的功能,然后将模块混入所谓的子类。这是书中提供的方法,也感觉不完美,没有了继承的感觉
  • 能否在父类中添加什么使其只可读不可写呢?
2.3 单表继承的优点和缺点

单表继承中所有的属性都存在于一张表中,这样真的好吗?如果子类存在的差异较大,且属性数据较大,如果仍然存在于同一张表,就会产生很多问题。这时可以学习多态继承了。

5. 参考

  • 《Web开发敏捷之道》第2版#P341-连接多张表

ActiveRecord-连接多张表之单表继承的更多相关文章

  1. python 存储引擎 mysql(库,表, 行) 单表多表操作 (foreign key) sql_mode pymysql模块讲解

    ##################总结############### mysql 常用数据类型 整型:tinyint  int(42亿条左右)  bigint 小数:float double dec ...

  2. django(七)之数据库表的单表-增删改查QuerySet,双下划线

    https://www.cnblogs.com/haiyan123/p/7738435.html https://www.cnblogs.com/yuanchenqi/articles/6083427 ...

  3. django之数据库表的单表查询

    一.添加表记录 对于单表有两种方式 # 添加数据的两种方式 # 方式一:实例化对象就是一条表记录 Frank_obj = models.Student(name ="海东",cou ...

  4. Django框架----数据库表的单表查询

    一.添加表记录 对于单表有两种方式 # 添加数据的两种方式 # 方式一:实例化对象就是一条表记录 Frank_obj = models.Student(name ="海东",cou ...

  5. python 之 数据库(修改表、复制表、删除表、单表查询)

    10.8 修改表.复制表.删除表 10.81 修改表 alter table . 修改表名 alter table 表名 rename 新表名; . 增加字段 alter table 表名 add 字 ...

  6. Mysql常用表操作 | 单表查询

    160905 常用表操作 1. mysql -u root -p 回车 输入密码   2. 显示数据库列表 show databases     3. 进入某数据库 use database data ...

  7. $Django orm增删改字段、建表 ,单表增删改查,Django请求生命周期

    1 orm介绍  ORM是什么   ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM.  一 ...

  8. python开发mysql:表关系&单表简单查询

    一 一对多,多对一 1.1 建立多对一 ,一对多的关系需要注意 先建立被关联的表,被关联的字段必须保证时唯一的 在创建关联的表,关联的字段一定是可以重复的 1.2 示例: 出版社 多对一,多个老师可能 ...

  9. day42——外键的限制和解决方法、外键的三种约束模式、修改表(单表查询)

    day42 外键的限制和解决方法 可以添加外键关联的那个字段可以是 被唯一(unique)约束的字段 或者 主键 限制:+ 由于外键的使用,致使多个表之间产生了联系,当我们对这些表进行更新或删除操作的 ...

随机推荐

  1. 卸载由源码编译安装的软件(如OpenCV)

    看安装软件的时候有没有使用--prefix这个参数,如果有那就把你指定的文件给删除了就行了. 如果没有用这个参数就麻烦一点了,那就进入到软件解压后的目录,执行sudo make uninstall看能 ...

  2. 学大伟业 Day 5 培训总结

    今天讲数据结构 先从mzx大佬的ppt摘抄一段: 数据结构是计算机存储.组织数据的方式.数据结构是指相互之间存在一种或多种特定关系的数据元素的集合. 通常情况下,精心选择的数据结构可以带来更高的运行或 ...

  3. 在CentOs6.5下安装Python2.7.6和Scrapy

    总在网上看大家的安装教程,这回自己也贡献一份!!! 和民航大学合作项目,去给人家装环境,连简单的Scrapy都没装上,虽然有对方硬件设施坑爹的因素,但主要还是自己准备不充分. 一份好的安装文档应该是可 ...

  4. 深入 Struts2 的配置 - 处理多个请求-处理请求结果-模型驱动-异常机制

    转:http://www.java3z.com/cwbwebhome/article/article2/2938.html?id=1631 本部分主要介绍struts.xml的常用配置. 1.1.   ...

  5. Unity3d-制作粒子光环特效

    http://blog.csdn.net/ozhangseno/article/details/70799611

  6. bitmap和drawable的相互转化以及setImageResource(),setImageDrawable(),setImageBitmap()

    从本地获取drawable图片:getResources().getDrawable(R.drawable.**) 获取bitmap:Bitmap b=BitmapFactory().decodeRe ...

  7. o'Reill的SVG精髓(第二版)学习笔记——第三章

    第三章:坐标系统 3.1视口 文档打算使用的画布区域称作视口.我们可以在<svg>元素上使用width和height属性确定视口的大小.属性的值可以是一个数字,该数字会被当作用户坐标下的像 ...

  8. 史上最简单的SpringCloud教程 | 第三篇: 服务消费者(Feign)(Finchley版本)

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f3-feign/ 本文出自方志朋的博客 上一篇文章,讲述了如 ...

  9. #leetcode刷题之路6- Z 字形变换

    将一个给定字符串根据给定的行数,以从上往下.从左到右进行 Z 字形排列.比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:L     C     I ...

  10. 二进制部署etcd集群

    kuberntes 系统使用 etcd 存储所有数据,本文档介绍部署一个三节点高可用 etcd 集群的步骤,这三个节点配置复用 ,我在这里没有做认证,如果有需要也可以做. 下载二进制文件 到 http ...