Aggregations - composed_of 方法

我们在一张表里有几个类似字段,比如 customers 表有 address_street, address_city 字段,用于保存地址信息。好的做法,当然是把它们拆分出来,单独做成 address 表。但如果我们不想/能折分表成的话(改动太大,处理遗留问题等),使用 composed_of 可以实现不用真正折分表,又能起到到分离的作用。

class Customer < ActiveRecord::Base
  composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
end

这里,把 address 当做关联对象。原 customer 的 address_street 和 address_city 分别映射成为 address 的 street 和 city 属性。

根据"约定优于配置",关联对象 address 对应 class Address,我们实现它:

class Address
  attr_reader :street, :city

  def initialize(street, city)
    @street, @city = street, city
  end
end

之后即可对 Address 的实例对象进行操作。

如何使用?

Customer 有 balance,address_street、address_city 字段。

class Customer < ActiveRecord::Base
  # 把 balance 当做关联对象,amount 映射成为它的属性;对应着 class Money
  composed_of :balance, class_name: "Money", mapping: %w(balance amount)

  # 把 address 当做关联对象,street 和 city 映射成为它的属性;对应着 class Address
  composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
end

可选参数 :class_name, :mapping, :allow_nil, :constructor, :converter,此外,你有下列读、写方法:

除了读、写方法外,composed_of 还创建管理了 Reflection 关联两者:

注意:我们没有 model Money 和 model Address,也没有它们对应的表,所以要实现其对应的 class,类似:

然后就能这么操作:

参考一下 has_one,让 composed_of 变得容易理解。使用 has_one 和 composed_of,两张表均属于一对一关系,只不过 composed_of 是我们想像出来的表,并不存在真正的数据库里。

Note: composed_of 创建的是'值对象',区别于一般的'实体对象'。值对象没有唯一身份标识,只有所有的值相等,两个值对象才相等;而实体对象,有唯一标识(如:id),只要唯一标识相等,两个实体对象就相等了。

可选参数详解

参数

解释

class_name

和其它关联一样,可以指定类名

mapping

旧字段与新字段的映射关系 旧字段在前,新字段在后

allow_nil

被关联的对象,其属性全部为空时,这个被关联的对象是否为 nil 对象 默认选项为 false

constructor

如何初始化值对象

converter

给值对象赋值时,如何处理

默认 关联对象只有在第一次调用,才会初始化 注意这个特点,否则你会发再一些奇怪现象。例如:

最后更新于

这有帮助吗?