В Руководстве по контекстам Phoenix есть раздел, в котором добавлено увеличение количества просмотров страниц. функциональность в фиктивный контекст CMS. Функция, созданная в контексте CMS, выглядит так:
def inc_page_views(%Page{} = page) do
{1, [%Page{views: views}]} =
from(p in Page, where: p.id == ^page.id, select: [:views])
|> Repo.update_all(inc: [views: 1])
put_in(page.views, views)
end
Перефразируя, inc_page_views
берет структуру Page
, использует ее id
для поиска соответствующей записи в базе данных, использует Repo.update_all
для атомарного увеличения счетчика просмотров (см. документацию для примера чередования), гарантирует, что была обновлена только 1 запись, и возвращает новую Page
с количество просмотров обновлений.
Почему в этом примере используется Ecto.Repo.update_all/3
, а не Ecto.Repo.update/2
? Поскольку мы знаем, что хотим работать только с одной записью, кажется странным потенциально обновлять кучу записей и задним числом проверять, что мы этого не сделали, вместо того, чтобы обновлять конкретный Ecto.Changeset
, что может выглядеть примерно так:
def inc_page_views(%Page{views: curr_views} = page) do
page
|> Page.changeset(%{views: curr_views + 1})
|> Repo.update()
end
Эта реализация короче/проще, но я предполагаю, что авторы документации Phoenix не использовали ее по уважительной причине. Я подозреваю, что в версии Repo.update
должно отсутствовать то свойство атомарного обновления, которое предположительно присутствует в версии Repo.update_all
, но я понятия не имею, почему! Может ли кто-нибудь помочь объяснить разницу между этими реализациями и почему документы могли выбрать первое?
Repo.update()
этого не делает. Мне нужно больше читать документы Ecto! 04.11.2019Repo.update
/update!
возьметchangeset
, аupdate_all
возьметqueryable
. Это означает, чтоupdate
неразрывно связан с шаблоном чтение, изменение (набор изменений), запись, аupdate_all
может выполнять все в одном запросе (выбрать-и-обновить). См. также эту ветку форума elixirforum. 30.01.2021