我有一个从Repo获取的模型,并预先加载了一些关联。我在GenServer中维护这个大型结构,但仍然保留对它的更改。我怎样才能坚持这些变化?例如:
query = from e in Empire,
where: e.user_id == ^user.id,
preload: [:board, {:board, [{:tiles, [:system]}]}]
empire = Repo.one(query)
#=> %Empire{
id: 1,
currency: 1000,
board: %Board{
empire_id: 1,
tiles: [
%Tile{
id: 1,
system: %System{
id: 1,
tile_id: 1,
ore: 10
}
},
%Tile{
id: 2,
system: nil
}
]
}
}
changed_empire = Empire.move_system(empire)
#=> %Empire{
id: 1,
currency: 500, #changed
board: %Board{
empire_id: 1,
tiles: [
%Tile{
id: 1,
system: nil #changed
}
},
%Tile{
id: 2,
system: %System{
id: 1,
tile_id: 2, #changed
ore: 5 #changed
}
]
}
}
请注意,系统已从一个平铺移动到另一个平铺,并且Empires货币已更改。更改可以包括添加或删除关联。所有这些都是在没有来自客户端的任何数据的情况下完成的,所以不必担心添加不良数据,因为服务器是如何操纵模型的唯一权威。
我不能依赖正常的
changeset(model, params \\ %{}) do
model
|> cast(params, [])
end
因为params将是结构。我可以尝试使用
建议的更改update_change(struct) do
struct
|> change()
|> validate()
end
但现在我遇到了需要手动发送到自己的update_change函数的关联结构的问题。
有没有更好的方法来实现这一点,而不会增加我似乎遇到的所有额外的复杂性?
答案 0 :(得分:0)
在评论的帮助下,我能够解决我的问题。我创建了一个小助手模块,它遍历所有数据并在其上调用Map.from_struct。这与常规演员/ 3相结合,给了我预期的结果。
这是帮助者:
defmodule RepoHelper do
def from_struct(struct) when is_map(struct) do
from(struct)
end
defp from(struct = %{__struct__: _}) do
Enum.reduce(Map.to_list(struct), struct, fn {key, val}, acc ->
Map.put(acc, key, from(val))
end)
|> Map.from_struct()
end
defp from(map) when is_map(map) do
Enum.reduce Map.to_list(map), map, fn {key, val}, acc ->
Map.put(acc, key, from(val))
end
end
defp from(list) when is_list(list) do
Enum.map list, fn item -> from(item) end
end
defp from(value), do: value
end