Rails复杂查询与多级关联

时间:2014-11-07 10:36:02

标签: ruby-on-rails activerecord

我有一个深层嵌套的布局如下:

合同 - >有很多包 - >有很多服务

付款 - > belongs_to发票 - > belongs_to合同

class Contract < ActiveRecord::Base
  has_many :invoices
  has_many :contract_packages
  has_many :packages, through: :contract_packages
end

class Package < ActiveRecord::Base
  has_many :services
  has_many :contract_packages
  has_many :contracts, through: :contract_packages
end

class ContractPackage < ActiveRecord::Base
  belongs_to :contract
  belongs_to :package
end

class Service < ActiveRecord::Base
  belongs_to :package
end

class Invoice < ActiveRecord::Base
  belongs_to :contract
end

class Payment < ActiveRecord::Base
  belongs_to :invoice
end

我想根据付款日期查找服务,以及在特定时间段内开具的帐单数量。发票日期可能与付款日期不同。

我知道用纯SQL来做它很热,而且它可以工作,但是如果我想以rails方式这样做,我就会陷入困境。

有什么想法吗?

编辑:

纯SQL查询:

select s.[name], count(*), s.[price] from payments p 
left join invoices i on p.invoice_id=i.id
left join contracts c on i.[contract_id]=c.id
left join contract_packages cp on cp.contract_id=c.id
left join packages pk on cp.[package_id]=pk.id
left join services s on s.package_id=pk.id
where ... conditions
group by s.id
order by s.id asc

在我原来的问题中,为简洁起见,我遗漏了一个联接表,因为一个包可能属于许多合同。这里的sql包含连接表。我也更新了模型。

1 个答案:

答案 0 :(得分:0)

只要您在模型中定义了关系,就可以直接在activerecord中进行连接。您只需将哈希传递给joins,它就会找出要使用的密钥。添加where条件可以类似的方式完成。

我注意到您的发票中没有has_many :payments这是设计的吗?在那种情况下为什么?

我编写的select子句将为使用此查询创建的所有Service对象提供额外的方法count,您可以在其中找到您的值。

Service.select('*, count(*) as count')
.joins({ 
  package: { 
    contract: {
      invoices: :payment
    } 
  }
})
.where(conditions_hash)
.group('services.id asc')
.order(:id)