Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 使用JOIN语句扩展ActiveRecord多态关联?_Mysql_Ruby On Rails_Ruby_Inheritance_Activerecord - Fatal编程技术网

Mysql 使用JOIN语句扩展ActiveRecord多态关联?

Mysql 使用JOIN语句扩展ActiveRecord多态关联?,mysql,ruby-on-rails,ruby,inheritance,activerecord,Mysql,Ruby On Rails,Ruby,Inheritance,Activerecord,我的表设置为子表与父表的关系为1:1 它们共享一个主键id: 父项具有id、类型和名称 孩子有身份证和健康 子对象是父对象的多态继承。我的目标是Child.find1应该返回一个响应name和health的子对象。SQL语句假设如下所示: class Child < ApplicationRecord self.table_name = "childs" belongs_to :parent, foreign_key: :id, dependent: :destroy dele

我的表设置为子表与父表的关系为1:1

它们共享一个主键id:

父项具有id、类型和名称 孩子有身份证和健康 子对象是父对象的多态继承。我的目标是Child.find1应该返回一个响应name和health的子对象。SQL语句假设如下所示:

class Child < ApplicationRecord
  self.table_name = "childs"
  belongs_to :parent, foreign_key: :id, dependent: :destroy
  delegate :name, :type, to: :parent
  delegate :name=, to: :parent, allow_nil: true

  after_initialize do
    self.build_parent(type: "Child") if parent.nil?
  end
end

class Parent < ApplicationRecord
  self.inheritance_column = 'foo' # otherwise, type column will be used for STI
  has_one :child, foreign_key: :id
  delegate :health, to: :child
end
irb(main):003:0> p = Parent.joins("LEFT JOIN childs ON (childs.id = parents.id)").select("parents.id, parents.name, childs.health").find(1)
  Parent Load (0.2ms)  SELECT  parents.id, parents.name, childs.health FROM "parents" LEFT JOIN childs ON (childs.id = parents.id) WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, name: "Hello">
irb(main):004:0> p.name
=> "Hello"
irb(main):005:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"
从parents中选择parents.id、parents.name、childs.health 左键连接childs.id=Parents.id上的childs 其中parents.id=1,parents.type='Child'限制为1

因此,我尝试在ActiveRecord中使用多态继承:

class Parent < ApplicationRecord
class Child < Parent
当我尝试执行Child.find1时,我看到:

从“parents”中选择“parents”。“parents”中键入“Child”和“parents”。“ID”=1限制1 =>

值得注意的是,子表上没有连接,但我收到了一个子对象。这会导致子对象不响应运行状况的意外行为。奇怪的是,如果我将显式表关联添加到子类self.table_name=childs,那么查询模式将更改为:

>c=Child.find1 可获得负载0.3ms从“childs”中选择“childs”。“ID”=2限制1

现在我可以访问运行状况,但不能访问类型或名称

如何正确创建此联接关联,以使加载子对象的尝试成功联接来自父对象的数据


编辑:这些表是在ActiveRecord迁移之外创建的,它们也被其他预先存在的非Ruby应用程序访问,因此我无法更改它们的模式。我可以想出一些奇特的元编程方法,比如响应方法_missing,这可能会让我通过连接延迟加载缺少的属性。。。但我担心我最终不得不重新实现一堆ActiveRecord,比如删除、创建等,这将导致bug。因此,我正在寻找一些本地/干净的方法来实现这一点。

这不是这里描述的典型Rails多态关联:

因此,在这种情况下,当其他应用程序较早创建表时,我建议您执行以下操作:

class Child < ApplicationRecord
  self.table_name = "childs"
  belongs_to :parent, foreign_key: :id, dependent: :destroy
  delegate :name, :type, to: :parent
  delegate :name=, to: :parent, allow_nil: true

  after_initialize do
    self.build_parent(type: "Child") if parent.nil?
  end
end

class Parent < ApplicationRecord
  self.inheritance_column = 'foo' # otherwise, type column will be used for STI
  has_one :child, foreign_key: :id
  delegate :health, to: :child
end
irb(main):003:0> p = Parent.joins("LEFT JOIN childs ON (childs.id = parents.id)").select("parents.id, parents.name, childs.health").find(1)
  Parent Load (0.2ms)  SELECT  parents.id, parents.name, childs.health FROM "parents" LEFT JOIN childs ON (childs.id = parents.id) WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, name: "Hello">
irb(main):004:0> p.name
=> "Hello"
irb(main):005:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"
现在,您可以访问运行状况、类型和名称:

> c = Child.joins(:parent).find(1)
  Child Load (0.2ms)  SELECT  "childs".* FROM "childs" INNER JOIN "parents" ON "parents"."id" = "childs"."id" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Child id: 1, health: "Good", created_at: "2016-10-27 21:42:55", updated_at: "2016-10-27 21:44:08">
irb(main):002:0> c.health
=> "Good"
irb(main):003:0> c.type
  Parent Load (0.1ms)  SELECT  "parents".* FROM "parents" WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Child"
irb(main):004:0> c.name
=> "Hello"
父母的情况也类似:

p = Parent.joins(:child).find(1)
  Parent Load (0.1ms)  SELECT  "parents".* FROM "parents" INNER JOIN "childs" ON "childs"."id" = "parents"."id" WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, type: nil, name: "Hello", created_at: "2016-10-27 21:40:35", updated_at: "2016-10-27 21:40:35">
irb(main):003:0> p.name
=> "Hello"
irb(main):004:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"
如果愿意,可以按如下方式指定左连接:

class Child < ApplicationRecord
  self.table_name = "childs"
  belongs_to :parent, foreign_key: :id, dependent: :destroy
  delegate :name, :type, to: :parent
  delegate :name=, to: :parent, allow_nil: true

  after_initialize do
    self.build_parent(type: "Child") if parent.nil?
  end
end

class Parent < ApplicationRecord
  self.inheritance_column = 'foo' # otherwise, type column will be used for STI
  has_one :child, foreign_key: :id
  delegate :health, to: :child
end
irb(main):003:0> p = Parent.joins("LEFT JOIN childs ON (childs.id = parents.id)").select("parents.id, parents.name, childs.health").find(1)
  Parent Load (0.2ms)  SELECT  parents.id, parents.name, childs.health FROM "parents" LEFT JOIN childs ON (childs.id = parents.id) WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, name: "Hello">
irb(main):004:0> p.name
=> "Hello"
irb(main):005:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"

这不是一个典型的Rails多态关联,如下所述:

因此,在这种情况下,当其他应用程序较早创建表时,我建议您执行以下操作:

class Child < ApplicationRecord
  self.table_name = "childs"
  belongs_to :parent, foreign_key: :id, dependent: :destroy
  delegate :name, :type, to: :parent
  delegate :name=, to: :parent, allow_nil: true

  after_initialize do
    self.build_parent(type: "Child") if parent.nil?
  end
end

class Parent < ApplicationRecord
  self.inheritance_column = 'foo' # otherwise, type column will be used for STI
  has_one :child, foreign_key: :id
  delegate :health, to: :child
end
irb(main):003:0> p = Parent.joins("LEFT JOIN childs ON (childs.id = parents.id)").select("parents.id, parents.name, childs.health").find(1)
  Parent Load (0.2ms)  SELECT  parents.id, parents.name, childs.health FROM "parents" LEFT JOIN childs ON (childs.id = parents.id) WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, name: "Hello">
irb(main):004:0> p.name
=> "Hello"
irb(main):005:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"
现在,您可以访问运行状况、类型和名称:

> c = Child.joins(:parent).find(1)
  Child Load (0.2ms)  SELECT  "childs".* FROM "childs" INNER JOIN "parents" ON "parents"."id" = "childs"."id" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Child id: 1, health: "Good", created_at: "2016-10-27 21:42:55", updated_at: "2016-10-27 21:44:08">
irb(main):002:0> c.health
=> "Good"
irb(main):003:0> c.type
  Parent Load (0.1ms)  SELECT  "parents".* FROM "parents" WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Child"
irb(main):004:0> c.name
=> "Hello"
父母的情况也类似:

p = Parent.joins(:child).find(1)
  Parent Load (0.1ms)  SELECT  "parents".* FROM "parents" INNER JOIN "childs" ON "childs"."id" = "parents"."id" WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, type: nil, name: "Hello", created_at: "2016-10-27 21:40:35", updated_at: "2016-10-27 21:40:35">
irb(main):003:0> p.name
=> "Hello"
irb(main):004:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"
如果愿意,可以按如下方式指定左连接:

class Child < ApplicationRecord
  self.table_name = "childs"
  belongs_to :parent, foreign_key: :id, dependent: :destroy
  delegate :name, :type, to: :parent
  delegate :name=, to: :parent, allow_nil: true

  after_initialize do
    self.build_parent(type: "Child") if parent.nil?
  end
end

class Parent < ApplicationRecord
  self.inheritance_column = 'foo' # otherwise, type column will be used for STI
  has_one :child, foreign_key: :id
  delegate :health, to: :child
end
irb(main):003:0> p = Parent.joins("LEFT JOIN childs ON (childs.id = parents.id)").select("parents.id, parents.name, childs.health").find(1)
  Parent Load (0.2ms)  SELECT  parents.id, parents.name, childs.health FROM "parents" LEFT JOIN childs ON (childs.id = parents.id) WHERE "parents"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, name: "Hello">
irb(main):004:0> p.name
=> "Hello"
irb(main):005:0> p.health
  Child Load (0.1ms)  SELECT  "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Good"

杰出的非标准问题的绝佳解决方案。但快速跟进:Child.new.save当前不会创建父对象,同样,delete也不会清理联接的表。我计划自己使用before_*filters来实现簿记,但我很好奇你是否有更好的主意。我编辑了子类,这样它会自动创建和删除父记录,例如c=Child.new,然后c.name=Foo c.save和删除c.destroy注意:这绝对不是典型的Rails方式,但它可以解决这个非标准问题。太棒了!非标准问题的绝佳解决方案。但快速跟进:Child.new.save当前不会创建父对象,同样,delete也不会清理联接的表。我计划自己使用before_*filters来实现簿记,但我很好奇你是否有更好的主意。我编辑了子类,这样它会自动创建和删除父记录,例如c=Child.new,然后c.name=Foo c.save和删除c.destroy注意:这绝对不是典型的Rails方式,但它可以解决这个非标准问题。