разработка экто-запросов на моих моделях схемы для поддержки предварительной загрузки - PullRequest
0 голосов
/ 18 декабря 2018

Итак, я пытаюсь получить шаблон для всех моих экто-моделей, имеющих дочерние ассоциации.

Иногда в моих контроллерах я хочу загрузить только модель, а в других случаях я хочу загрузить ее со всемиили некоторые из ассоциаций.

def get_account!(id), do: Repo.get!(Account, id)

У учетной записи есть следующие ассоциации:

has_many :users
belongs_to :company

Что было бы хорошим способом изменить мой get_account!функция, которая дает мне возможность предварительно загружать ассоциации?

Я не хочу, чтобы этот код предварительной загрузки был в моих контроллерах, мне нравится иметь все мои связанные с запросами вещи в самом модуле и не просачиваться в мои контроллеры.

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Я обычно заимствую подход из того, как создаются области Rails.Экто запрос принимает другой запрос в качестве источника.В качестве последнего вызова следует вызывать функции семейства Repo.get, фактически выполняющие запрос к базе данных, когда к запросу добавляются все предварительные загрузки и другие условия.

Таким образом, вы можете ввести пустой шаблонный запрос, например::

defp do_get_account_query(id),
  do: from(a in Account, where: a.id == ^id)

И используйте его во всех ваших запросах с помощью Ecto.Repo.one!/2:

def get_account!(id, preloads \\ []) do
  preloads
  Enum.reduce(do_get_account_query(id), fn clause, query ->
    Repo.preload(query, clause)
  end)
  |> Repo.one!()
end

Для более сложных областей можно использовать универсальную функцию ивывести из него сферу.

0 голосов
/ 18 декабря 2018

Один из способов сделать это - создать with_<association> функции в вашем контекстном модуле, например:

def get_account!(id), do: Repo.get!(Account, id)

def with_company(%Account{} = account), do: Repo.preload(account, :company)

def with_users(%Account{} = account), do: Repo.preload(account, :users)

, чтобы вы могли использовать их в своем контроллере следующим образом:

def show(conn, %{"id" => id}) do
  account = 
    Context.get_account!(id)
    |> Context.with_company
    |> Context.with_users
  render(conn, "show.html", account: account)
end

и у вас есть полностью загруженная учетная запись, доступная в представлении.

Хорошая особенность этого подхода заключается в том, что вы можете легко расширить его с помощью более специфических предварительных загрузок, например account |> with_most_active_users(10).

...