我有一个为用户分配多种技能的功能。这些技能已经存在,并且与用户具有many_to_many
关系。
# skills will look like [%{id: "1"}, %{id: "4"}, %{id: "5"}] etc.
def reset(user, skills) do
user
|> Repo.preload(:skills)
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:skills, [])
|> Repo.update()
ids = Enum.map(skills, &Map.get(&1, :id))
query = Repo.all(from(p in Skill, where: p.id in ^ids))
skills = Enum.each(query, &Skill.create(user, &1))
end
目前可以,但是效率低下:
Repo.all
来获取技能,只要存在ID,就可以通过ID加入它们Ecto.Multi
中以提高数据库效率除此之外,还可以返回创建的技能,而不仅仅是返回:ok
返回的Enum.each
原子。
重构代码的最佳方法是什么?
答案 0 :(得分:2)
一项改进就是不将一项技能一一分配给
def reset(user, skills) do
ids = Enum.map(skills, &Map.get(&1, :id))
skills = Repo.all(from(p in Question.Skill, where: p.id in ^ids))
user
|> Repo.preload(:skills)
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:skills, skills)
|> Repo.update()
end
如果不需要进行任何更改(即对用户技能的任何删除或补充),这将对数据库进行两次查询(假设尚未加载:skills
,否则将只有一个查询,正在获取技能)。
此外,因为我们正在进行变更集,所以它不会重置整个事情。它只会删除或添加必要的内容。