2016-12-05 3 views
0

Ich habe folgendes Schema:für Primärschlüssel und Validierung

@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 

Wie kann ich eine Zahl für das Feld erzeugen number, wenn ein changeset wird durch die Registerfunktion schaffen werden?

Wie kann ich zuerst die Datenbank validieren, wenn die Nummer bereits verfügbar ist oder nicht, um Doppelungen zu vermeiden.

+1

Gibt es einen Grund, warum Sie keine automatische Inkrement-Taste dafür verwenden? – Dogbert

+0

Ja, weil ich die Nummer als ID verwenden möchte. Ist es nicht eine gute Übung? –

+1

Was meinst du mit "generiere eine Nummer" dann? Ein ganzzahliger Schlüssel mit automatischem Inkrement würde Datensätze mit den Werten 0, 1, 2, ... erzeugen. – Dogbert

Antwort

2

Hier ist eine Möglichkeit, eine Spalte zu erstellen, die bei 1000000 beginnt und automatisch einen eindeutigen Wert zuweist, der ungefähr dem vorherigen Wert +1 entspricht (grob weil eine ID wegen fehlgeschlagener Transaktionen und möglicherweise anderer Fälle "übersprungen" werden könnte)).

Diese Antwort ist spezifisch für PostgreSQL, da sie die PostgreSQL-spezifischen Funktionen setval und pg_get_serial_sequence verwendet.

Migration:

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 

Modell:

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 

Demo:

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>} 

Einige Anmerkungen:

  • gesetzt ich 999999 den Sequenzwert die nächste Zahl in der Folge 1000000

  • ist

    I read_after_writes: true auf die Säule gegeben, um sicherzustellen, da der Wert für dieses Feld von der Datenbank erzeugt wird, und ohne read_after_writes Satz zu true, das Feld wird nach dem Einfügen nicht erneut geladen und bleibt nil.

+0

Vielen Dank für Ihre Hilfe. Bist du im Elixir-Team? Ich habe noch eine Frage, schauen Sie sich den folgenden Code an (https://github.com/kostonstyle/relation/blob/master/priv/repo/migrations/20161203214117_create_countries_languages.exs) und beachten Sie die 'countries_codes' Tabelle , wäre nicht besser, iso als Primärschlüssel statt Standard "id" zu verwenden. Später werden in der Tabelle "countries" länder_Codes für Constraint verwendet. –

Verwandte Themen