预加载有很多通过关联

时间:2017-09-27 13:56:09

标签: elixir phoenix-framework ecto

如何通过关联预加载多个?

设置

mix phx.new shop
cd shop
mix echo.create
mix phx.gen.html Accounting Invoice invoices number issued_on:date
mix phx.gen.html Accounting Product products name price:integer
mix phx.gen.html Accounting LineItem line_items 
                                     invoice_id:references:invoices 
                                     product_id:references:products
mix ecto.migrate

PRIV /回购/ seeds.exs

{:ok, invoice1} = Shop.Accounting.create_invoice(%{number: "1", issued_on: "2017-01-01"})
{:ok, invoice2} = Shop.Accounting.create_invoice(%{number: "2", issued_on: "2017-01-01"})
{:ok, invoice3} = Shop.Accounting.create_invoice(%{number: "3", issued_on: "2017-01-02"})

{:ok, banana} = Shop.Accounting.create_product(%{name: "Banana", price: 1})
{:ok, apple} = Shop.Accounting.create_product(%{name: "Apple", price: 2})

Shop.Accounting.create_line_item(%{invoice_id: invoice1.id, product_id: banana.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice2.id, product_id: banana.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice2.id, product_id: apple.id})
Shop.Accounting.create_line_item(%{invoice_id: invoice3.id, product_id: apple.id})

模式

LIB /商店/计费/ invoice.ex

schema "invoices" do
  field :issued_on, :date
  field :number, :string
  has_many :line_items, Shop.Accounting.LineItem
  has_many :products, through: [:line_items, :products]

  timestamps()
end

LIB /商店/计费/ line_item.ex

schema "line_items" do
  belongs_to :invoice, Shop.Accounting.Invoice
  belongs_to :product, Shop.Accounting.Product

  timestamps()
end

LIB /商店/计费/ product.ex

schema "products" do
  field :name, :string
  field :price, :integer

  timestamps()
end

查询发票预加载产品

使用以下代码,我尝试查询1月1日至1月5日的所有invoices,包括products。没有preload它就可以了。我需要更改哪些内容才能预加载products

import Ecto.Query
alias Shop.Accounting.Invoice
alias Shop.Repo

{:ok, starts_on} = Date.from_erl({2017, 1, 1})
{:ok, ends_on} = Date.from_erl({2017, 1, 5})


query = from i in Invoice, where: i.issued_on >= ^starts_on,
                           where: i.issued_on <= ^ends_on,
                           preload: [:products]
invoices = Repo.all(query)

我收到此错误:

iex(15)> invoices = Repo.all(query)
[debug] QUERY OK source="invoices" db=2.6ms decode=0.1ms
SELECT i0."id", i0."issues_on", i0."number", i0."inserted_at", i0."updated_at" FROM "invoices" AS i0 WHERE (i0."issues_on" >= $1) AND (i0."issues_on" <= $2) [{2017, 1, 1}, {2017, 1, 5}]
[debug] QUERY OK source="line_items" db=2.8ms
SELECT l0."id", l0."invoice_id", l0."product_id", l0."inserted_at", l0."updated_at", l0."invoice_id" FROM "line_items" AS l0 WHERE (l0."invoice_id" = ANY($1)) ORDER BY l0."invoice_id" [[3, 2, 1]]
** (UndefinedFunctionError) function nil.__struct__/0 is undefined or private
    nil.__struct__()
    (elixir) lib/enum.ex:1811: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1811: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1811: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto) lib/ecto/repo/queryable.ex:139: Ecto.Repo.Queryable.execute/5
    (ecto) lib/ecto/repo/queryable.ex:37: Ecto.Repo.Queryable.all/4
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:438: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:219: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:200: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:178: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:77: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:21: IEx.Evaluator.init/4

1 个答案:

答案 0 :(得分:1)

以下是发票中的错误:

has_many :products, through: [:line_items, :products]

产品是复数。您应该使用单数product代替:

has_many :products, through: [:line_items, :product]

这是因为在订单项中您有单一产品:

belongs_to :product, Shop.Accounting.Product

has_many through跟随已描述的关联。