Ecto:如何预加载has_many关联的belongs_to关联?

时间:2017-04-17 09:18:23

标签: elixir phoenix-framework ecto

我有Meetup模型has_many :rsvpsRsvp模型belongs_to :user

这是我的终点:

def index(conn, _params) do
  one_hour_ago = Timex.now
                 |> Timex.shift(hours: -1)
                 |> Timex.to_unix
  meetups = from(m in Meetup, where: m.timestamp >= ^one_hour_ago)
            |> Repo.all
            |> Repo.preload(:rsvps)
  render conn, meetups: meetups
end

和我的观点

def render("index.json", %{ meetups: meetups }) do
  render_many(meetups, ParrotApi.MeetupView, "meetup.json")
end

def render("meetup.json", %{ meetup: meetup }) do
  %{
    id: meetup.id,
    rsvped_users: Enum.map(meetup.rsvps, fn rsvp ->
      rsvp |> Repo.preload(:user)
      user = rsvp.user
      %{
        image_url: user.image_url,
        interests: user.interests,
      }
    end),
  }
end

然而,** (Plug.Conn.WrapperError) ** (KeyError) key :image_url not found in: #Ecto.Association.NotLoaded<association :user is not loaded>

失败了

Repo导入视图感觉不对。有没有办法在控制器中执行此操作?

1 个答案:

答案 0 :(得分:1)

为此,Ecto支持嵌套预加载。你只需要改变:

|> Repo.preload(:rsvps)

为:

|> Repo.preload(rsvps: [:user])

在控制器中,所有Meetup的所有RSVP都会有效地预加载user字段。

你几乎从不在循环中调用preload(for / Enum.each / Enum.map等),因为它违背了预加载的主要目的 - avoiding N+1 queries。< / p>