2016-12-05 115 views
0

自定義數字我有以下模式:生成主鍵和確認

@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一個數字,當變更將通過寄存器功能創建?

我如何可以驗證第一數據庫中,如果數字是已經可用,避免重複。

+1

你不使用這個自動增量鍵的原因嗎? – Dogbert

+0

是的,因爲我想使用數字作爲ID。這不是一個好習慣嗎? –

+1

那麼你是什麼意思「生成一個數字」呢?有自動遞增的整數鍵將創建具有值0,1,2條記錄,... – Dogbert

回答

2

這裏有一種方法來創建開始於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,場插入後不會重新加載,並且將保持nil

+0

非常感謝您的幫助。你在仙丹隊嗎?我有一個問題,看看下面的[在GitHub代碼(https://github.com/kostonstyle/relation/blob/master/priv/repo/migrations/20161203214117_create_countries_languages.exs)和'countries_codes'表關注,使用iso作爲主鍵而不是默認的'id'會更好。之後,'countries'表將使用'countries_codes'來約束。 –