1

我正在为具有以下数据关系的仓储/运输公司开发一个程序。关于以下关系的细枝末节是,仓库从各种承运人(客户)那里接收原材料(产品)并将它们存储起来,直到需要将它们运送到制造工厂。当货物离开仓库时,制造工厂必须知道每种原材料来自哪家公司。看看下面的 ERD。 在此处输入图像描述

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

装运.rb

has_many :product_shipments, :dependent => :destroy
has_many :products, :through => :product_shipments

product_shipment.rb

belongs_to :product
belongs_to :shipment

产品.rb

has_many :product_shipments
has_many :shipments, :through => :product_shipments, :dependent => :destroy
belongs_to :client

客户端.rb

  has_many :products, :dependent => :destroy

我无法以符合要求的方式生成查询。发货报告需要一个日期,并且必须遍历每个客户并列出在该给定日期运送到制造工厂的产品。它需要动态生成并格式化如下。

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 生成查询。在下面的给定日期获取货物和产品很容易。获取原材料来源的原始客户,然后动态地迭代运送到该客户的制造设施并不容易。

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

@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 年 6 月 30 日发货的产品。从这个角度来看,查询变得古怪。当关系离得太远时,我不确定如何生成带有活动记录的查询。

4

2 回答 2

1

更新:好的,看看您在报告中期望的结果,需要从 ProductShipment 中提取值(如数量属性),因此 product_shipments 必须包含在我们急切加载的嵌套关联中,否则 ProductShipments 不会实例化,它仅用作连接表。

因此,而不是Client.includes(:products => shipments)...你想要:

@clients = Client.includes(:products => {:product_shipments => :shipment}).
                  where("shipments.ship='#{ship_date}'")

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

因此,您可以写(尊重得墨忒耳定律):

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

后者实际上会触发一个数据库调用......(我们试图避免)。值得庆幸的是,Rails 的口袋里还有另一个窍门:

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 并获取您的报告,而无需在 DB 上调用 O(n) :

@client.map {|c| c.products.map {|p| p.product_shipments} }.flatten.each do |ps|
  puts ps.details
end

更新结束


您必须急切加载相关模型,否则您将进入臭名昭著的 O(n) 查询。

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

顺便说一句,假设您在此处有has_many :throughorhas_and_belongs_to_many关联,则直接从发货到产品进行连接,因此无需使用连接表(又名 product_shipment)

于 2013-01-11T16:37:07.223 回答
0

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

@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
于 2013-01-13T02:04:25.473 回答