如何在Ecto中实现同时支持binary_id或字符串参数的查询
Ecto binary_id合法性判断
不需要正则校验,直接使用Ecto内置的类型能力即可实现校验:
- 如果你使用Ecto默认的UUID类型作为binary_id,直接调用
Ecto.UUID.dump/1即可:返回{:ok, _}说明是合法binary_id,返回:error则为不合法。
示例代码:defp valid_binary_id?(str) when is_binary(str) do match?({:ok, _}, Ecto.UUID.dump(str)) end - 如果你使用自定义类型作为binary_id,可以通过Schema的字段定义获取类型后调用
Ecto.Type.cast/2校验:
示例代码:@user_id_type Ecto.Schema.__field__(MyProject.Accounts.User, :id).type defp valid_binary_id?(str) when is_binary(str) do match?({:ok, _}, Ecto.Type.cast(@user_id_type, str)) end
优雅的多条件查询实现
你不需要编写两份完全重复的查询逻辑,可以通过动态拼接查询条件实现需求,避免非合法binary_id和id字段比较触发CastError:
import Ecto.Query def get_user(id_or_username) do match_conditions = if valid_binary_id?(id_or_username) do dynamic([u], u.id == ^id_or_username or u.username == ^id_or_username) else dynamic([u], u.username == ^id_or_username) end MyProject.Accounts.User |> where([u], is_nil(u.deleted_at)) |> where(^match_conditions) |> MyProject.Repo.one() end
原报错原因说明
Ecto在查询构建阶段就会对参数做类型校验,你将非合法binary_id的字符串和UUID类型的id字段做等值比较时,Ecto会提前尝试转换参数类型,转换失败就会直接抛出CastError,不会等到查询实际执行。因此只需要在构建查询时,判断入参类型后再决定是否加入id匹配条件即可。
内容的提问来源于stack exchange,提问作者Freedom_Ben
相关产品推荐
相关产品推荐

