为主键和验证生成自定义编号
Generate custom number for primary key and validation
我有以下架构:
@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
生成编号?
如果号码已经可用或不可用,我如何首先验证数据库以避免重复。
这是创建一个从 1000000 开始的列并自动分配一个唯一值的方法,该值大致等于前一个值 + 1(大致是因为 id 可能是 "skipped",因为交易失败并且可能其他一些情况)。
此答案特定于 PostgreSQL,因为它使用特定于 PostgreSQL 的 setval
和 pg_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 (,) 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 (,) 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 (,) 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
,该字段将插入后不会重新加载,将保持 nil
.
我有以下架构:
@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
生成编号?
如果号码已经可用或不可用,我如何首先验证数据库以避免重复。
这是创建一个从 1000000 开始的列并自动分配一个唯一值的方法,该值大致等于前一个值 + 1(大致是因为 id 可能是 "skipped",因为交易失败并且可能其他一些情况)。
此答案特定于 PostgreSQL,因为它使用特定于 PostgreSQL 的 setval
和 pg_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 (,) 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 (,) 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 (,) 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
,该字段将插入后不会重新加载,将保持nil
.