几天前,我开始在Postgres数据库中使用Elixir和Phoenix框架(V0.12.0).我正在try 创建一个具有UUID主键的表,我更喜欢它,而不是顺序默认值.

在使用mix phoenix.gen.html生成模型和迁移文件,并遵循Phoenix文档中的其他步骤之后,我已经改变了

def model do
    quote do
      use Ecto.Model
    end
  end

web.ex

def model do
  quote do
    use Ecto.Model
    @primary_key {:id, :uuid, []}
    @foreign_key_type :uuid
  end
end

正如外太空文件中提到的.我还将迁移更改为

create table(:tblname, primary_key: false) do
  add :id, :uuid, primary_key: true
  [other columns]
end

不幸的是,当我试图从自动生成的表单向表中添加一个条目时,我得到了一个错误,因为id是空的.如果我手动将id列添加到模型中,我会收到一个错误,即该列已经存在.如果我在table/2中忽略将primary_key设置为false,并删除id列,那么该表将生成一个连续的id列.

我是否需要在变更集中手动设置id,或者在设置应用程序以使用UUID时出错?提前谢谢

推荐答案

编辑:我已将此答案更新为EXTO v2.0.你可以在最后阅读上一个答案.

埃克托v2

从最初的答案开始,在Exto中处理UUID变得更加直截了当.Exto有两种ID::id:binary_id.第一个是我们从数据库中知道的整数ID,第二个是特定于数据库的二进制文件.对于博士后来说,这是一个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选项时,EXTO将保证适配器或数据库将为您生成它.但是,如果愿意,您仍然可以手动生成它.顺便说一句,您可以在迁移中使用:uuid,在模式中使用Ecto.UUID,而不是:binary_id:binary_id的好处是它可以跨数据库移植.

外胚层v1

您需要告诉数据库如何自动生成UUID.或者您需要从应用程序端生成一个.这取决于你喜欢哪一个.

在我们继续之前,有一点很重要,那就是您使用的:uuid将返回二进制文件,而不是人类可读的UUID.您很可能希望使用Ecto.UUID,它将把它格式化为字符串(aaaa bbb ccc-…)这就是我下面要用到的.

在数据库中生成

在迁移中,为字段定义默认值:

add :id, :uuid, primary_key: true, default: fragment("uuid_generate_v4()")

我假设你正在运行PostgreSQL.您需要在pgAdmin中安装uuid ossp扩展,或者在迁移中添加execute "CREATE EXTENSION \"uuid-ossp\"".更多关于the UUID generator can be found here的信息.

回到EXTO,在您的模型中,要求EXTO在插入/更新后从数据库中读取字段:

@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是一个回调函数,它将使用给定的参数在给定的函数中调用给定的模块,并将一个表示插入内容的变更集作为第一个参数.

就这些了.顺便说一句,future 这项工作可能会更加精简.:)

Postgresql相关问答推荐

PostgreSQL数据文件是否仅在判断点期间写入磁盘?

在postgres中查找多个表中不同列的计数和总和

如何在PostgreSQL中正确删除数据库

在同一 Select 列表中两次使用jsonb_arrayElements()是否安全?

ANTLR4 PostgreSQL语法被 destruct 了吗?

Postgres 11没有强制执行外键约束?

对 VOLATILE 函数的调用会 destruct SELECT 语句的原子性

JOOQ:数据库版本早于 COCKROACHDB 支持的方言:13.0.0

如何为基于复合类型的 Postgres DOMAIN 定义 CHECK 约束

获取 OperationalError: FATAL: sorry, too many clients already using psycopg2

在 postgres 中删除所有共享相同前缀的表

SQLAlchemy 和多个进程的连接问题

在 PostgreSQL 中显示正在运行的查询的全文

Postgres 外键on update和on delete选项如何工作?

如何在带有 PostgreSQL 数据库的 Web 应用程序中拥有完整的离线功能?

将数据从 MS SQL 迁移到 PostgreSQL?

无法在 postgresql hibernate 中使用名为user的表

PostgreSQL 9 在 Windows 上安装:Unable to write inside TEMP environment path.

如何减少存储(缩减)我的 RDS 实例?

PostgreSQL - pg_config -bash:pg_config:command not found