几天前,我开始使用Elixir和Postgres数据库的Phoenix Framework(v 0.12.0)。我正在尝试创建一个具有UUID主键的表,而我更喜欢该表优于顺序默认值。
使用mix phoenix.gen.html
生成模型和迁移文件并遵循Phoenix文档中的其他步骤,我已更改
def model do
quote do
use Ecto.Model
end
end
在 web.ex
to
def model do
quote do
use Ecto.Model
@primary_key {:id, :uuid, []}
@foreign_key_type :uuid
end
end
如ecto文档中所述。我也将迁移更改为
create table(:tblname, primary_key: false) do
add :id, :uuid, primary_key: true
[other columns]
end
不幸的是,当我尝试从自动生成的表单中添加一个条目时,我会遇到一个错误,因为id
为null。如果我将id
-Column手动添加到模型中,我会收到列已经存在的错误。如果我忽略了将primary_key
设置为table/2
中的false并删除id
列,则该表是使用顺序id
-Column生成的。
我是否需要在更改集中手动设置id
,还是在设置应用程序使用UUID时犯了错误?预先感谢
编辑:我将此答案更新为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}
当您为:binary_id
指定:autogenerate
选项时,ECTO将确保适配器或数据库为您生成它。但是,如果愿意,您仍然可以手动生成它。顺便说一句,您可以在迁移中使用:uuid
,而在架构中使用Ecto.UUID
,而不是:binary_id
,:binary_id
的好处是它在数据库中是可移植的。
ecto v1
您需要告诉数据库如何自动为您生成UUID。或者,您需要从应用程序端生成一个。这取决于您喜欢哪个。
在我们继续前进之前,必须说您使用的是:uuid
,它将返回二进制文件,而不是人类可读的UUID。您很可能要使用Ecto.UUID
将其格式化为字符串(AAAAAA-BBB-CCC -...),这就是我在下面使用的。
在数据库中生成
在您的迁移中,为字段定义一个默认值:
add :id, :uuid, primary_key: true, default: fragment("uuid_generate_v4()")
我假设您在PostgreSQL上运行。您需要在PGADMIN中使用CREATE EXTENSION "uuid-ossp"
安装UUID-OSSP扩展名,或在迁移中添加execute "CREATE EXTENSION "uuid-ossp""
。有关UUID发电机的更多信息可以在此处找到。
回到eTo,在您的模型中,请插入/更新后从数据库中读取字段:
@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
是一个回调,它将用给定参数在给定函数处调用给定模块,而更改表示被插入的内容作为第一个参数。
应该全部。顺便说一句,将来有可能会更简化这一点。:)
也创建新项目通行选项--binary-id
将UUID用作默认主键。
mix phx.new project_name --binary-id