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


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

    1. 基本概念

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

    2. 单表继承

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

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

    # model的定义
    class People < ActiveRecord::Base
    end
    
    class Customer < People
    end
    
    class Employee < People
        belongs_to :boss, class_name: 'Employee', foreign_key: 'reports_to'
    end
    
    class Manager < Employee
    end
    # 迁移文件的定义,即关系型数据库的体现
    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-连接多张表
  • 相关阅读:
    SharePoint:扩展DVWP 第33部分:修改DVWP中的合计和分类汇总
    通过SharePoint Web服务更新审批状态
    SharePoint:扩展DVWP 第29部分:修改Remove模版上的表单操作工作流
    SharePoint:扩展DVWP 第27部分:为DVWP添加一个备用编辑模版
    SharePoint 2010之Visio Services入门1-2-3
    一步一步开发属于自己的SharePoint 2010工作流
    在SharePoint 2010中创建自定义字段类型
    SharePoint:扩展DVWP 第25部分:通过SPServices创建列表项实现审计跟踪
    欢迎参加天津PDC Party的活动
    SharePoint:扩展DVWP 赠送部分:当“找不到匹配项”时修复Insert表单操作
  • 原文地址:https://www.cnblogs.com/arrongao/p/4658280.html
Copyright © 2020-2023  润新知