使用Ecto.Query查询具有UUID的表会产生Ecto.Query.CastError

时间:2017-10-17 20:45:15

标签: postgresql elixir phoenix-framework ecto

所以我有以下迁移:

create table(:things, primary_key: false) do
  add :id, :uuid, primary_key: true
  add :state, :string

  timestamps()
end

具有以下架构:

@primary_key {:id, Ecto.UUID, autogenerate: true}
@derive {Phoenix.Param, key: :id}
schema "things" do
  field :state, :string

  timestamps()
end

在REPL中尝试以下查询后,我得到Ecto.Query.CastError

iex(8)> q = from s in Thing, where: s.id == "ba34d9a0-889f-4999-ac23-f04c7183f2ba", select: s
#Ecto.Query<from o in App.Thing,
 where: o.id == "ba34d9a0-889f-4999-ac23-f04c7183f2ba", select: o>
iex(9)> Repo.get!(Thing, q)
** (Ecto.Query.CastError) /project/deps/ecto/lib/ecto/repo/queryable.ex:341: value `#Ecto.Query<from o in App.Thing, where: o.id == "ba34d9a0-889f-4999-ac23-f04c7183f2ba", select: o>` in `where` cannot be cast to type Ecto.UUID in query:

from o in App.Thing,
  where: o.id == ^#Ecto.Query<from o in App.Thing, where: o.id == "ba34d9a0-889f-4999-ac23-f04c7183f2ba", select: o>,
  select: o

    (elixir) lib/enum.ex:1811: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1357: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (elixir) lib/enum.ex:1811: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto) lib/ecto/repo/queryable.ex:124: Ecto.Repo.Queryable.execute/5
    (ecto) lib/ecto/repo/queryable.ex:37: Ecto.Repo.Queryable.all/4
    (ecto) lib/ecto/repo/queryable.ex:78: Ecto.Repo.Queryable.one!/4
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (iex) lib/iex/evaluator.ex:219: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:200: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:178: IEx.Evaluator.eval/3

我不确定这是将UUID与Ecto一起使用的正确方法,我环顾四周,但有几个人在做不同的事情。我正在使用Ecto 2.1和Postgres 10.0与postgrex

有关如何正确查询Ecto并投射UUID的任何提示?

编辑:我在查询中提供的ID是我从数据库中复制的实际现有ID。

1 个答案:

答案 0 :(得分:1)

我发现您遇到的问题最初有点令人困惑,但我认为它运作正常 - 问题在于您如何查询数据库。

如果您已准备好查询,则需要使用Repo.all(query),因此您的代码应为:

q = from s in Thing, where: s.id == "ba34d9a0-889f-4999-ac23-f04c7183f2ba", select: s
Repo.all(q)

您可以查询数据库以按主键查找特定记录,这时您可以使用Repo.get!/3

试试这个:

Repo.get!(Thing, "ba34d9a0-889f-4999-ac23-f04c7183f2ba")

当您将q作为第二个参数传递给get!时,它会尝试将其转换为UUID,但事实上,查询不是可投射,这在例外中解释:

** (Ecto.Query.CastError) /project/deps/ecto/lib/ecto/repo/queryable.ex:341: value `#Ecto.Query<from o in App.Thing, where: o.id == "ba34d9a0-889f-4999-ac23-f04c7183f2ba", select: o>` in `where` cannot be cast to type Ecto.UUID in query:

你能看到整个#Ecto.Query<>被包含在``

您可以在文档中找到更多信息:

希望有所帮助!