The*_*uts 21 postgresql elixir ecto phoenix-framework
几天前,我开始使用Elixir和Phoenix Framework(v 0.12.0)和Postgres数据库.我正在尝试创建一个具有UUID主键的表,我更喜欢顺序默认值.
在使用mix phoenix.gen.html
生成模型和迁移文件并遵循Phoenix文档中的其他步骤之后,我已经更改了
def model do
quote do
use Ecto.Model
end
end
Run Code Online (Sandbox Code Playgroud)
在web.ex
以
def model do
quote do
use Ecto.Model
@primary_key {:id, :uuid, []}
@foreign_key_type :uuid
end
end
Run Code Online (Sandbox Code Playgroud)
正如Ecto文档中提到的那样.我也将迁移更改为
create table(:tblname, primary_key: false) do
add :id, :uuid, primary_key: true
[other columns]
end
Run Code Online (Sandbox Code Playgroud)
不幸的是,当我尝试从自动生成的表单向表中添加一个条目时,我收到一个错误,因为它id
是null.如果我手动将id
-column 添加到模型中,则会收到列已存在的错误.如果我忽略设置primary_key
为false table/2
并删除id
列,则使用顺序id
列生成表.
我是否需要id
在变更集中手动设置,或者在设置我的应用程序以使用UUID时出错?提前致谢
Jos*_*lim 42
编辑:我已将此答案更新为Ecto v2.0.您可以在最后阅读上一个答案.
自最初答案以来,处理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
Run Code Online (Sandbox Code Playgroud)
然后在您的模型模块中(schema
块外):
@primary_key {:id, :binary_id, autogenerate: true}
Run Code Online (Sandbox Code Playgroud)
当您指定:autogenerate
选项时:binary_id
,Ecto将保证适配器或数据库将为您生成它.但是,如果您愿意,仍然可以手动生成它.顺便说一句,您可以:uuid
在迁移和Ecto.UUID
架构中使用,而不是:binary_id
,它的好处:binary_id
是它可以跨数据库移植.
您需要告诉数据库如何自动为您生成UUID.或者您需要从应用程序端生成一个.这取决于你喜欢哪一个.
在我们继续之前,重要的是要说你正在使用:uuid
它将返回二进制文件而不是人类可读的UUID.你很可能想要使用Ecto.UUID
它将其格式化为一个字符串(aaaa-bbb-ccc -...),这就是我将在下面使用的内容.
在迁移中,为字段定义默认值:
add :id, :uuid, primary_key: true, default: fragment("uuid_generate_v4()")
Run Code Online (Sandbox Code Playgroud)
我假设你在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}
Run Code Online (Sandbox Code Playgroud)
现在,当您插入时,数据库将生成一个默认值,Ecto将读回它.
您需要定义一个为您插入UUID的模块:
defmodule MyApp.UUID do
def put_uuid(changeset) do
Ecto.Changeset.put_change(changeset, :id, Ecto.UUID.generate())
end
end
Run Code Online (Sandbox Code Playgroud)
并将其用作回调:
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
Run Code Online (Sandbox Code Playgroud)
before_insert
是一个回调函数,它将使用给定的参数调用给定函数的给定模块,其中一个变量集表示作为第一个参数给出的插入内容.
这应该是全部.顺便说一下,未来有可能会更精简.:)
同样,在创建新的项目传递选项时--binary-id
,使用UUID作为默认主键。(启动Ecto v2)
mix phx.new project_name --binary-id
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6834 次 |
最近记录: |