首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Rails 3.2基于复杂关系组织报告

Rails 3.2基于复杂关系组织报告
EN

Stack Overflow用户
提问于 2013-01-11 10:35:33
回答 2查看 246关注 0票数 1

我正在为一家仓储/航运公司开发一个具有以下数据关系的程序。关于下面的关系,最基本的是仓库从不同的承运商(客户)接收原材料(产品),并存储它们,直到需要将它们运往制造工厂。当一批货物离开仓库时,制造工厂必须知道每种原材料来自哪个公司。看看下面的ERD。

编辑:我的文本形式的关系。

shipment.rb

代码语言:javascript
运行
复制
has_many :product_shipments, :dependent => :destroy
has_many :products, :through => :product_shipments

product_shipment.rb

代码语言:javascript
运行
复制
belongs_to :product
belongs_to :shipment

product.rb

代码语言:javascript
运行
复制
has_many :product_shipments
has_many :shipments, :through => :product_shipments, :dependent => :destroy
belongs_to :client

client.rb

代码语言:javascript
运行
复制
  has_many :products, :dependent => :destroy

我在生成查询时遇到了问题,因为查询的格式不符合需求的要求。发货报告需要一个日期,并且必须遍历每个客户,并列出在该给定日期发运到制造工厂的产品。它需要像下面这样动态生成和格式化。

代码语言:javascript
运行
复制
Shipment Date: 2013-01-01

Client: 12 Name: ACME Widget Co

Product Name | Product Code | Qty Shipped
_________________________________________ 
nuts & bolts |      gj-3423 |          25
steel sheet  |      4g-2394 |          10
dc Motor     |      cj-c213 |           4


Client: 14 Name: Blah Blah, Inc

Product Name | Product Code | Qty Shipped
_________________________________________ 
spacers      |      gj-3423 |          15
epoxy        |      4g-2394 |          10
dc Motor     |      24-gj19 |           6

Client: 15 Name: Sample Co, Inc

Product Name | Product Code | Qty Shipped
_________________________________________ 
hot roll 48  |      cg-3423 |          15
welding wir  |      4g-2394 |          10
dc Motor     |      c2-1241 |           6
.
.
.
.

问题是使用ActiveRecord生成查询。在下面的ex中,很容易获取给定日期的发货和产品。要获取原材料来源的原始客户,然后动态地迭代发货到该客户的制造设施并不容易。

更新:我现在可以像上面那样对客户和发货进行分组。现在,我需要排除那些没有在指定日期发货的客户。下面的内容虽然有些正确,但仍然给出了可怕的O(n)查询。这是我所拥有的。

代码语言:javascript
运行
复制
@clients = Client.includes(:products => :shipments)
@clients.each do |c|
  puts c.name
  c.products.each do |p|
    p.shipments.where("ship_date like '#{@ship_date.strftime("%Y-%m-%d")}%'").each do |s|
      s.product_shipments.joins(:product).each do |ps|
        puts s.bill_of_lading + " " + ps.product_id.to_s + " " + ps.product.product_name.to_s + " " + ps.product.product_code + " " +ps.qty_shipped.to_s + " " + s.ship_date.to_s
        end
    end
  end
end

我的问题是,我如何组织查询,从客户开始,然后列出'2012-06-30发货的产品。从这个角度来看,查询变得很古怪。当关系被移除那么远时,我不确定如何生成带有活动记录的查询。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-13 10:04:25

这就是我是如何做到的。也许不是最好的方法,但也很接近。感谢@charlysisto将我引导到正确的方向,并轻松加载关系。我在查找表的连接查询上仍然得到O(n),但可能会更糟。任何改进,请评论,以便我可以改善答案。

代码语言:javascript
运行
复制
@clients = Client.order("clients.id ASC").includes(:products => :shipments).where("shipments.ship_date like '#{ship_date}'")
@clients.each do |c|
  puts c.name
  c.products.each do |p|
    p.shipments.each do |s|
      s.product_shipments.joins(:product).each do |ps|
        puts shipment and products stuff
      end
    end
end
票数 0
EN

Stack Overflow用户

发布于 2013-01-12 00:37:07

更新:好的,看看你在报告中预期的结果,来自ProductShipment的值(像数量属性)需要被提取出来,所以product_shipments必须包括在我们急于加载的嵌套关联中,否则ProductShipments不会被实例化,它只用作一个连接表。

因此,您需要的不是Client.includes(:products => shipments)...而是:

代码语言:javascript
运行
复制
@clients = Client.includes(:products => {:product_shipments => :shipment}).
                  where("shipments.ship='#{ship_date}'")

现在我不能完全理解你的领域模型,但当有很多嵌套的关联时,我喜欢找出在一对一关系中包含最多信息的关联,因为它们可以被视为中心部分。在这种情况下,产品和发货都可以理解为“主模型”product_shipment的扩展。

因此,你可以这样写(尊重德米特定律):

代码语言:javascript
运行
复制
class ProductShipment < AR
  def report_details
    s = shipment; p = product
    "#{s.bill_of_lading} #{p.id} #{p.name} #{p.code} #{quantity} #{s.shipped_on}"
  end
end

这就是棘手的部分:正如它所写的那样,:products => {:product_shipments => :shipment} Rails能够理解

product_shipments.shipment,但不是product_shipment.products

后者实际上会触发一个db调用。(这是我们试图避免的)。值得庆幸的是,Rails还有另一个窍门:

代码语言:javascript
运行
复制
class ProductShipment < ActiveRecord::Base
  belongs_to :product, inverse_of: :product_shipments
end

class Product < ActiveRecord::Base
  has_many :product_shipments, inverse_of: :product
end

确保关联的镜像后,您现在可以通过产品获取product_shipments,并在数据库上不需要O(n)调用即可获得报告:

代码语言:javascript
运行
复制
@client.map {|c| c.products.map {|p| p.product_shipments} }.flatten.each do |ps|
  puts ps.details
end

更新结束

您必须立即加载关联的模型,否则会得到臭名昭著的O(n)查询。

代码语言:javascript
运行
复制
Shipment.where(:date => someday).includes({:product => :client}).each do |shipmt|
  puts shipmt.date

  shipmt.product.group_by(&:client).each do |client, products|
    puts client

    products.each do |product|
      puts product.details
    end
  end
end

顺便说一句,rails直接从发货到产品连接,假设您在这里有一个has_many :throughhas_and_belongs_to_many关联,所以不需要使用连接表(也称为product_shipment)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14270777

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档