【问题标题】:Generate custom number for primary key and validation为主键和验证生成自定义数字
【发布时间】:2017-04-20 00:19:12
【问题描述】:

我有以下架构:

  @primary_key false
  schema "companies" do
    field :number,         :integer, primary_key: true
    field :name,           :string
    field :street,         :string
    field :zipcode,        :integer
    field :location,       :string
    field :phone,          :integer
    field :company_class,  :string
    field :country_iso,    :string
    field :email,          :string
    field :password,       :string, virtual: true
    field :password_hash,  :string
    has_many :contacts,    Busiket.Contact, on_delete: :delete_all

    timestamps
  end

  def register(struct, params \\ %{}) do

  end

当通过注册函数创建变更集时,如何为字段number 生成一个数字?

我如何首先验证数据库,如果该号码已经可用或不可用,以避免重复。

【问题讨论】:

  • 有什么理由不使用自动增量键吗?
  • 是的,因为我想使用数字作为 id。这不是一个好习惯吗?
  • 那么“生成一个数字”是什么意思?具有自动增量的整数键将创建值为 0、1、2、...的记录
  • 我将生成一个数字,它总是有 7 个数字,例如:1000554 或 `4117455'。
  • 这将是一个客户编号。 @Dogbert 这是一个好习惯吗?

标签: elixir ecto


【解决方案1】:

这是一种创建从 1000000 开始的列并自动分配一个唯一值的方法,该值大致等于前一个值 + 1(大致是因为由于事务失败和其他一些情况可能会“跳过”一个 id) .

此答案特定于 PostgreSQL,因为它使用 PostgreSQL 特定的 setvalpg_get_serial_sequence 函数。

迁移:

defmodule MyApp.Repo.Migrations.CreateCompany do
  use Ecto.Migration

  def up do
    create table(:companies, primary_key: false) do
      add :number, :serial, primary_key: true
      timestamps()
    end
    execute "select setval(pg_get_serial_sequence('companies', 'number'), 999999)"
  end

  def down do
    drop table(:companies)
  end
end

型号:

defmodule MyApp.Company do
  use MyApp.Web, :model

  @primary_key false
  schema "companies" do
    field :number, :integer, primary_key: true, read_after_writes: true

    timestamps()
  end
end

演示:

iex(1)> Repo.insert! %Company{}
[debug] QUERY OK db=2.7ms queue=0.1ms
INSERT INTO "companies" ("inserted_at","updated_at") VALUES ($1,$2) RETURNING "number" [{{2016, 12, 5}, {15, 57, 44, 0}}, {{2016, 12, 5}, {15, 57, 44, 0}}]
%MyApp.Company{__meta__: #Ecto.Schema.Metadata<:loaded, "companies">,
 inserted_at: #Ecto.DateTime<2016-12-05 15:57:44>, number: 1000000,
 updated_at: #Ecto.DateTime<2016-12-05 15:57:44>}
iex(2)> Repo.insert! %Company{}
[debug] QUERY OK db=4.5ms
INSERT INTO "companies" ("inserted_at","updated_at") VALUES ($1,$2) RETURNING "number" [{{2016, 12, 5}, {15, 57, 44, 0}}, {{2016, 12, 5}, {15, 57, 44, 0}}]
%MyApp.Company{__meta__: #Ecto.Schema.Metadata<:loaded, "companies">,
 inserted_at: #Ecto.DateTime<2016-12-05 15:57:44>, number: 1000001,
 updated_at: #Ecto.DateTime<2016-12-05 15:57:44>}
iex(3)> Repo.insert! %Company{}
[debug] QUERY OK db=3.4ms queue=0.1ms
INSERT INTO "companies" ("inserted_at","updated_at") VALUES ($1,$2) RETURNING "number" [{{2016, 12, 5}, {15, 57, 45, 0}}, {{2016, 12, 5}, {15, 57, 45, 0}}]
%MyApp.Company{__meta__: #Ecto.Schema.Metadata<:loaded, "companies">,
 inserted_at: #Ecto.DateTime<2016-12-05 15:57:45>, number: 1000002,
 updated_at: #Ecto.DateTime<2016-12-05 15:57:45>}

一些注意事项:

  • 我将序列值设置为999999,以确保序列中的下一个数字是1000000

  • 我在列中添加了read_after_writes: true,因为该字段的值是由数据库生成的,并且没有将read_after_writes设置为true,插入后该字段不会重新加载,将保持@987654332 @。

【讨论】:

  • 非常感谢您的帮助。你在灵药队吗?我还有一个问题,看看下面的code on github 并注意countries_codes 表,使用iso 作为主键而不是默认的id 不是更好。稍后,countries 表将使用countries_codes 进行约束。
猜你喜欢
  • 2013-02-15
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
相关资源
最近更新 更多