基于Elixir thread from last year,我能够编写原始SQL查询来使用不相关表中的值批量更新记录。但是,我希望能够使用Ecto生成此查询。
在下面的示例中,假设有两个表cats和dogs,并且cats表具有外键(dog_id)。我想把狗和猫联系起来。
下面的代码是我如何使用Elixir和原始SQL手动执行此操作:
cat_ids = [1,2,3] # pretend these are uuids
dog_ids = [4,5,6] # ... uuids
values =
cat_ids
|> Enum.zip(dog_ids)
|> Enum.map(fn {cat_id, dog_id} ->
"('#{cat_id}'::uuid, '#{dog_id}'::uuid)"
end)
|> Enum.join(", ")
sql = """
UPDATE cats as a
SET dog_id = c.dog_id
from (values #{values}) as c(cat_id, dog_id)
where c.cat_id = a.id;
"""
Repo.query(sql)
是否可以将其移动到Repo.update_all或使用某些片段,以便不手动构建查询?
答案 0 :(得分:0)
当然,您可以使用Ecto语法,但是在我看来,它并没有太大不同,例如,您必须使用Schema,例如,在我的应用程序中,我具有用户身份验证,这就是我们更新令牌的方式:>
def update_token(user_id, token) do
Repo.transaction(fn ->
from(t in UserAuthentication, where: t.user_id == ^to_string(user_id))
|> Repo.update_all(set: [token: token])
end
和UserAuthentication架构大致类似:
defmodule MyApp.UserAuthentication do
use Ecto.Schema
import Ecto.Changeset
schema "user_authentication" do
field(:user_id, :integer)
field(:token, :string)
timestamps()
end
def changeset(%__MODULE__{} = user, attrs) do
user
|> cast(attrs, [:user_id, :token])
|> validate_required([:user_id, :token])
end
end
这对数据验证很有用,并且可以在您连接的任何数据库中使用。