【问题标题】:How to make a query with multiple relations?如何进行具有多个关系的查询?
【发布时间】:2020-09-17 11:18:20
【问题描述】:

假设:

class Item < ApplicationRecord
  has_many :rowbills, dependent: :destroy
end

class Rowbill < ApplicationRecord
  belongs_to :invoice, inverse_of: :rowbills
  belongs_to :item
end

class Invoice < ApplicationRecord
  belongs_to :customer
end

class Customer < ApplicationRecord
  has_many :invoices
end

我想知道是否可以从 Items 开始检索 Rowbills、Invoices 和 Customers 上的某些字段?

我想我应该这样加入我的桌子吗?

Item.joins(rowbills: {invoice: customer})

Item.includes(rowbills: {invoice: customer})

这里是 schema.rb 的摘录(我只留下了我想恢复的字段)

create_table "items", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
  t.string   "label"
end

create_table "rowbills", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
  t.decimal  "total_price_vat_excluded_cache", precision: 8,  scale: 2, default: "0.0"
  t.integer  "invoice_id"
  t.integer  "item_id"
  t.index ["invoice_id"], name: "index_rowbills_on_invoice_id", using: :btree
  t.index ["item_id"], name: "index_rowbills_on_item_id", using: :btree
end

create_table "invoices", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
  t.integer  "customer_id"
  t.index ["customer_id"], name: "index_invoices_on_customer_id", using: :btree
end

create_table "customers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
  t.string   "name"
end

我想浏览这些项目以在最后得到类似的东西:

items: [
  {
    label: "First Item",
    customers: [
      {
        name: "First Customer",
        total_price_vat_excluded_cache: "600.0",
      },
      {
        name: "Second Customer",
        total_price_vat_excluded_cache: "400.0",
      }
    ]
  },
  {
    label: "Second Item",
    customers: [
      {
        name: "First Customer",
        total_price_vat_excluded_cache: "200.0",
      }
    ]
  }
]

我希望我说清楚了,提前感谢那些可以帮助我的人。

【问题讨论】:

    标签: mysql ruby-on-rails ruby


    【解决方案1】:

    您想要创建可以让您遍历“树”的间接关联:

    class Item < ApplicationRecord
      has_many :rowbills, dependent: :destroy
      has_many :invoices, through: :rowbills
      has_many :customers, through: :invoices
    end
    
    class Rowbill < ApplicationRecord
      belongs_to :invoice, inverse_of: :rowbills
      belongs_to :item
    end
    
    class Invoice < ApplicationRecord
      belongs_to :customer
      has_many :rowbills
      has_many :products, through: :rowbills
    end
    
    class Customer < ApplicationRecord
      has_many :invoices
      has_many :items, through: :invoices
    end
    

    the has_many through: association

    这让您可以通过item.customers 获取每件商品的客户(请注意潜在的 n+1 查询)。

    Rowbill 听起来也像某种鸭子。订单或发票上每一行的常用术语是line item

    【讨论】:

    • 如果n+1有问题,可以使用条件选项,即has_many :what_ever, -&gt; {includes(:through_relationship)}, through: :through_relationship
    • @Int'lManOfCodingMystery 我不想详细说明和转移话题,但实际上你可以只做Item.includes(:customers),rails 也会处理包括连接表。
    • 是的,我的意思是如果他们想通过默认的关系进行急切加载。只是一个临时的建议就是全部:D
    【解决方案2】:

    我认为Item.includes(...) 很好。
    代码匹配我的结果就像

      items = Item
                .includes(rowbills: {invoice: customer})
                .map do |it|
                  {
                    label: it.label,
                    customer: it.rowbills.map do |bill|
                      {
                        name: bill.invoice.customer.name,
                        total_price_vat_excluded_cache: bill.total_price_vat_excluded_cache} }
                      }
                    end
                  }
                end
    

    “包含”方法会急切地加载关系

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-21
      • 1970-01-01
      • 2019-03-28
      相关资源
      最近更新 更多