编辑:我已将此答案更新为 Ecto v2.0。您可以在最后阅读上一个答案。
Ecto v2
自最初的答案以来,在 Ecto 中处理 UUID 变得更加直接。Ecto 有两种类型的 ID::id
和:binary_id
. 第一个是我们从数据库中知道的整数 ID,第二个是数据库特定的二进制文件。对于 Postgres,它是一个 UUID。
要将 UUID 作为主键,首先在迁移中指定它们:
create table(:posts, primary_key: false) do
add :id, :binary_id, primary_key: true
end
然后在您的模型模块中(schema
块外):
@primary_key {:id, :binary_id, autogenerate: true}
当您为 指定:autogenerate
选项时:binary_id
,Ecto 将保证适配器或数据库将为您生成它。但是,如果您愿意,您仍然可以手动生成它。顺便说一句,您可以:uuid
在迁移和Ecto.UUID
架构中使用而不是:binary_id
,这样做的好处:binary_id
是它可以跨数据库移植。
Ecto v1
您需要告诉您的数据库如何为您自动生成 UUID。或者您需要从应用程序端生成一个。这取决于你喜欢哪一个。
在我们继续之前,重要的是要说您正在使用:uuid
它将返回二进制文件而不是人类可读的 UUID。您很可能希望使用Ecto.UUID
将其格式化为字符串(aaaa-bbb-ccc-...),这就是我将在下面使用的。
在数据库中生成
在您的迁移中,为该字段定义一个默认值:
add :id, :uuid, primary_key: true, default: fragment("uuid_generate_v4()")
我假设您在 PostgreSQL 上运行。您需要CREATE EXTENSION "uuid-ossp"
在 pgAdmin 中安装 uuid-ossp 扩展或添加execute "CREATE EXTENSION \"uuid-ossp\""
迁移。有关UUID 生成器的更多信息,请参见此处。
回到 Ecto,在您的模型中,让 Ecto 在插入/更新后从数据库中读取字段:
@primary_key {:id, Ecto.UUID, read_after_writes: true}
现在,当您插入时,数据库将生成一个默认值,而 Ecto 会读回它。
在应用程序中生成
您需要定义一个为您插入 UUID 的模块:
defmodule MyApp.UUID do
def put_uuid(changeset) do
Ecto.Changeset.put_change(changeset, :id, Ecto.UUID.generate())
end
end
并将其用作回调:
def model do
quote do
use Ecto.Model
@primary_key {:id, Ecto.UUID, []}
@foreign_key_type Ecto.UUID
before_insert MyApp.UUID, :put_uuid, []
end
end
before_insert
是一个回调,它将使用给定的参数在给定的函数处调用给定的模块,其中一个变更集表示正在插入的内容作为第一个参数给出。
这应该就是全部了。顺便说一句,将来有可能会更加精简。:)