Заблокировать строку «ДЛЯ ОБНОВЛЕНИЯ » конкретной таблицы с использованием Ecto / Elixir

#elixir #ecto

#elixir #ecto

Вопрос:

Я хотел бы получить lock using FOR UPDATE OF table_name . По сравнению с FOR UPDATE , FOR UPDATE OF блокирует только строку в указанной таблице, а объединенные строки не блокируются. Однако, когда я пытаюсь сделать это с помощью Ecto, используя следующий фрагмент, это не удается.

 query =
  Call
  |> join_other_tables() # custom methods
  |> Query.lock("FOR UPDATE OF calls")
  

Причина в том, что Ecto использует псевдоним для calls , например, c0 , что означает, что я также должен использовать псевдоним в выражении блокировки, чтобы заставить его работать.

 query =
  Call
  |> join_other_tables() # custom methods
  |> Query.lock("FOR UPDATE OF c0")
  

Использование псевдонима не похоже на правильный способ сделать это. Есть ли какой-либо другой способ заставить ее работать?

Ответ №1:

По состоянию на Ecto v3 нет способа передать параметризованное значение в Query.lock . Он принимает только двоичные файлы.

[Именованные привязки] также не будут работать, потому что Ecto внутренне генерирует псевдонимы по своему усмотрению.


Следующий подход был бы ближайшим, но он также не работает, потому что Ecto.Query.lock/2 не допускает интерполяции.

Используйте Ecto.Query.API.fragment , который имеет возможность интерполяции, с синтаксисом запроса ключевого слова. Что-то вроде:

 from c in Call,
  join: ..., # custom methods
  lock: fragment("FOR UPDATE OF ?", c)
  

Комментарии:

1. Это выдает следующую ошибку: fragment("FOR UPDATE OF ?", c) is not a valid lock. For security reasons, a lock must always be a literal string

2. Черт возьми, действительно они разрешают там только двоичные файлы. Тогда вы могли бы попробовать именованную привязку . Дайте мне знать, если это удастся, я либо обновлю ответ, либо удалю его.

3. К сожалению, это тоже не работает. Похоже, что Ecto использует эти псевдонимы внутренне, но для фактического SQL-запроса он по-прежнему генерирует новые псевдонимы .

4. Да, и генератор является частным. Извините, что говорю это, но похоже, что вам следует остановиться на последнем средстве: "c0" жестко закодированном. Я удалю ответ.

5. Или добавьте обновление к ответу, что в настоящее время нет способа сделать это, начиная с версии Ecto версии 3.

Ответ №2:

Обратите внимание, похоже, что теперь вы можете использовать фрагмент для интерполяции имени таблицы в, см. https://github.com/elixir-ecto/ecto_sql/pull/189 . Таким образом, решение от Алексея теперь должно работать:

 from c in Call,
  join: ..., # custom methods
  lock: fragment("FOR UPDATE OF ?", c)