【问题标题】:Association on Remote Databases in RailsRails 中的远程数据库关联
【发布时间】:2014-09-05 16:32:08
【问题描述】:

我正在尝试在我无法控制的数据库中的两个视图之间建立关联。这是人和工作之间的关系,每个人都有很多工作,每个工作都属于一个人。这是 person 表:

class Person < ActiveRecord::Base
  self.table_name = 'PER_VW'
  self.primary_key = 'EMPLID'

  has_many :jobs, foreign_key: 'EMPLID'
end

还有工作表:

class Job < ActiveRecord::Base
  self.table_name = 'JOB_VW'

  belongs_to :person, foreign_key: 'EMPLID'
end

从控制台我可以运行Person.where(emplid: '0037485').jobs,我没有收到错误,但我也没有得到任何结果。如果我改为这样做:

p = Person.where(emplid: '0037485').first()
Job.where(emplid: p.emplid)

我得到了我期望的结果。它是一个 oracle 数据库,我正在使用以下 gem 进行连接:

gem 'ruby-oci8', '~> 2.1.7'
gem "activerecord-oracle_enhanced-adapter", "~> 1.5.0"

编辑:根据 Lurker 的建议,我将 foreign_key: 'EMPLID' 添加到两个表中,但仍然没有得到任何结果。这是我在控制台中看到的这条 SQL:

irb(main):004:0> p.jobs
Job Load (36.5ms)  SELECT "JOB_VW".* FROM "JOB_VW"  
WHERE "JOB_VW"."EMPLID" = :a1  [[nil, nil]]
=> #<ActiveRecord::Associations::CollectionProxy []>

我想[nil, nil] 数组与它有关。但我不确定为什么它会是空的。

【问题讨论】:

  • 除了我之前的建议之外,我认为Person.where(emplid: '0037485').jobs 是不正确的,因为where 返回一个集合,在这种情况下,它是一个由一个项目组成的集合。根据我更新的答案,尝试从集合中获取“第一个”项目。
  • 我希望Person.where(emplid: '0037485').jobs 在没有.first 的情况下抛出错误。令人费解的是,为什么 p.jobsp = Person.where(emplid: '0037485').first 时空空如也。如果是,那么我更新的建议可能无法完全解决这个问题。
  • 这是一个非常直接的关联,应该可以工作。我在 Rails 的远程 MS SQL 数据库中使用了这个和其他一些更复杂的关系,它工作正常。 Oracle 适配器可能有问题。您是否可以选择其他适配器来尝试?
  • 感谢您提供一些建议。我一定在链中有.first,只是没有正确地将其复制到我的问题中,因为它没有引发错误。我更新了问题以包含它。我会看看是否可以找到替代适配器。问题是否也与我的Job 模型没有主键有关?视图中没有明确定义,但我可以找出一个复合键。
  • 这是个好问题。我不明白为什么 Job 模型中缺少主键会干扰创建有效查询以获取与给定员工 ID 关联的工作。但是,可能在重要的方法内部。

标签: ruby-on-rails ruby oracle ruby-on-rails-4 associations


【解决方案1】:

当关联中有外键时,需要在其他模型中指定:

class Job < ActiveRecord::Base
  self.table_name = 'JOB_VW'

  belongs_to :person, foreign_key: 'EMPLID'
end

否则,它将假定person_id

在简单的情况下,根据您的应用对模型所做的操作,您可以在 Person 模型中从 has_many 中省略 foreign_key。无论如何,我通常都将它包含在两个模型中。

编辑:当您进行查询时,关联会在实例上运行,而不是在集合上运行。因此,与其Person.where(emplid: '0037485').jobs 尝试为由一个人组成的ActiveRecord 关系获取jobs,不如尝试这种方式,获取集合中的第一个人,然后获取工作:

Person.where(emplid: '0037485').first.jobs

或者,由于员工 ID 是主键,这可能会起作用:

Person.find('0037485').jobs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2012-05-15
    • 1970-01-01
    • 2015-04-18
    相关资源
    最近更新 更多