如何设置Absinthe Schema使字段名与底层Ecto字段名不同?
解决Ecto与Absinthe的字段映射问题
嘿,别担心,这个需求其实有几种简单的实现方式,不一定非要用虚拟字段,我给你拆解一下:
方法1:在Absinthe Resolver中直接重映射(最省心)
这种方式不需要修改你的Ecto Schema,只需要在解析数据的时候把inserted_on的值赋值给created_at字段即可。
首先修改你的Absinthe Schema,把字段名改成前端需要的created_at:
defmodule MyAppWeb.Schema.AccountTypes do use Absinthe.Schema.Notation object :user do field :id, :id field :email, :string field :created_at, :datetime # 这里改成前端需要的字段名 end end
然后在对应的Resolver里,查询到用户数据后手动映射字段:
defmodule MyAppWeb.Resolvers.AccountResolver do def get_user(_parent, %{id: id}, _resolution) do with %{} = user <- MyApp.Accounts.get_user!(id) do # 把数据库字段的值赋给前端需要的字段 user_with_renamed_field = %{user | created_at: user.inserted_on} {:ok, user_with_renamed_field} end end end
方法2:给Ecto Schema添加虚拟字段(适合多场景复用)
如果你希望在多个业务场景里都能直接用created_at这个字段,而不是每次解析都手动映射,那可以给Ecto Schema添加虚拟字段:
修改你的Ecto Schema:
defmodule MyApp.Accounts.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :email, :string field :inserted_on, :utc_datetime # 数据库原字段 field :created_at, :utc_datetime, virtual: true # 添加虚拟字段,不对应数据库列 end # 可选:如果是新增用户,可在changeset里同步赋值 def changeset(user, attrs) do user |> cast(attrs, [:email]) |> validate_required([:email]) |> put_change(:created_at, DateTime.utc_now()) end end
之后在查询用户数据时,你可以直接把inserted_on的值同步到created_at:
# 方式1:查询后手动赋值 user = MyApp.Accounts.get_user!(id) %{user | created_at: user.inserted_on} # 方式2:用Ecto查询直接别名 from u in MyApp.Accounts.User, select: %{u | created_at: u.inserted_on}, where: u.id == ^id
方法3:用Absinthe Middleware统一处理(适合批量重命名)
如果你的项目中有大量字段需要做这种重映射,那可以写一个自定义的Absinthe Middleware来统一处理,避免重复代码。不过这种方式相对复杂,更适合大型项目的批量场景。
总结
- 如果只是单个字段、单个类型的需求,方法1最直接,改动最小;
- 如果多个业务场景都需要用到
created_at,方法2的虚拟字段方案更方便; - 批量重命名需求可以考虑方法3的Middleware方案。
内容的提问来源于stack exchange,提问作者Michael Johnston
相关产品推荐
相关产品推荐

