设置Phoenix框架和ECTO以使用UUID:如何插入生成的值



几天前,我开始使用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

最新更新