88 Stimmen

Wie kann ich mit Rails meinen Primärschlüssel so einstellen, dass es sich nicht um eine Spalte mit dem Typ Integer handelt?

Ich verwende Rails-Migrationen, um ein Datenbankschema zu verwalten, und ich erstelle eine einfache Tabelle, in der ich einen nicht-ganzzahligen Wert als Primärschlüssel verwenden möchte (insbesondere eine Zeichenfolge). Um von meinem Problem zu abstrahieren, nehmen wir an, es gibt eine Tabelle employees wobei die Mitarbeiter durch eine alphanumerische Zeichenfolge identifiziert werden, z. B. "134SNW" .

Ich habe versucht, die Tabelle in einer Migration wie dieser zu erstellen:

create_table :employees, {:primary_key => :emp_id} do |t|
    t.string :emp_id
    t.string :first_name
    t.string :last_name
end

Das Ergebnis ist, dass die folgende Zeile anscheinend völlig ignoriert wurde t.string :emp_id und machte daraus eine Integer-Spalte. Gibt es eine andere Möglichkeit, wie Rails die PRIMARY_KEY-Beschränkung (ich verwende PostgreSQL) für mich generieren kann, ohne dass ich die SQL in einer execute anrufen?

ANMERKUNG : Ich weiß, dass es nicht am besten ist, String-Spalten als Primärschlüssel zu verwenden, also bitte keine Antworten, die nur sagen, dass man einen Integer-Primärschlüssel hinzufügen soll. Ich werde vielleicht trotzdem einen hinzufügen, aber die Frage ist immer noch gültig.

108voto

Rudd Zwolinski Punkte 25176

Leider habe ich festgestellt, dass es nicht möglich ist, dies zu tun, ohne execute .

Warum es nicht funktioniert

Wenn wir den ActiveRecord-Quellcode untersuchen, können wir den Code für create_table :

En schema_statements.rb :

def create_table(table_name, options={})
  ...
  table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
  ...
end

Wir können also sehen, dass, wenn Sie versuchen, einen Primärschlüssel in der create_table Optionen, wird ein Primärschlüssel mit dem angegebenen Namen erstellt (oder, wenn keiner angegeben wird, id ). Dies geschieht durch den Aufruf der gleichen Methode, die Sie auch in einem Tabellendefinitionsblock verwenden können: primary_key .

En schema_statements.rb :

def primary_key(name)
  column(name, :primary_key)
end

Dies erzeugt einfach eine Spalte mit dem angegebenen Namen vom Typ :primary_key . In den Standard-Datenbankadaptern ist dies wie folgt eingestellt:

PostgreSQL: "serial primary key"
MySQL: "int(11) DEFAULT NULL auto_increment PRIMARY KEY"
SQLite: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"

Die Abhilfe

Da wir mit diesen Typen als Primärschlüssel feststecken, müssen wir execute um einen Primärschlüssel zu erstellen, der keine ganze Zahl ist (PostgreSQL's serial ist eine ganze Zahl, die eine Sequenz verwendet):

create_table :employees, {:id => false} do |t|
  t.string :emp_id
  t.string :first_name
  t.string :last_name
end
execute "ALTER TABLE employees ADD PRIMARY KEY (emp_id);"

Und als Sean McCleary erwähnt sollte Ihr ActiveRecord-Modell den Primärschlüssel mit set_primary_key :

class Employee < ActiveRecord::Base
  set_primary_key :emp_id
  ...
end

21voto

Austin Punkte 3842

Das funktioniert:

create_table :employees, :primary_key => :emp_id do |t|
  t.string :first_name
  t.string :last_name
end
change_column :employees, :emp_id, :string

Es mag nicht schön sein, aber das Endergebnis ist genau das, was Sie wollen.

18voto

Sean McCleary Punkte 3530

Ich habe eine Möglichkeit, damit umzugehen. Das ausgeführte SQL ist ANSI-SQL, so dass es wahrscheinlich mit den meisten ANSI-SQL-kompatiblen relationalen Datenbanken funktionieren wird. Ich habe getestet, dass dies für MySQL funktioniert.

Migration:

create_table :users, :id => false do |t|
    t.string :oid, :limit => 10, :null => false
    ...
end
execute "ALTER TABLE users ADD PRIMARY KEY (oid);"

Tun Sie dies in Ihrem Modell:

class User < ActiveRecord::Base
    set_primary_key :oid
    ...
end

11voto

Pavel Chuchuva Punkte 21957

In Rails 5 können Sie Folgendes tun

create_table :employees, id: :string do |t|
  t.string :first_name
  t.string :last_name
end

Véase create_table Dokumentation .

10voto

Arup Rakshit Punkte 113145

Ich habe es in Rails 4.2 ausprobiert. Um Ihren benutzerdefinierten Primärschlüssel hinzuzufügen, können Sie Ihre Migration als :

# tracks_ migration
class CreateTracks < ActiveRecord::Migration
  def change
    create_table :tracks, :id => false do |t|
      t.primary_key :apple_id, :string, limit: 8
      t.string :artist
      t.string :label
      t.string :isrc
      t.string :vendor_id
      t.string :vendor_offer_code

      t.timestamps null: false
    end
    add_index :tracks, :label
  end
end

Bei der Durchsicht der Dokumentation von column(name, type, options = {}) und lesen Sie die Zeile :

Les type Parameter ist normalerweise einer der nativen Typen der Migration, der einer der folgenden ist: :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :time, :date, :binary, :boolean.

Ich habe die oben genannten Ideen, wie ich gezeigt habe. Hier sind die Metadaten der Tabelle nach der Ausführung dieser Migration:

[arup@music_track (master)]$ rails db
psql (9.2.7)
Type "help" for help.

music_track_development=# \d tracks
                    Table "public.tracks"
      Column       |            Type             | Modifiers
-------------------+-----------------------------+-----------
 apple_id          | character varying(8)        | not null
 artist            | character varying           |
 label             | character varying           |
 isrc              | character varying           |
 vendor_id         | character varying           |
 vendor_offer_code | character varying           |
 created_at        | timestamp without time zone | not null
 updated_at        | timestamp without time zone | not null
 title             | character varying           |
Indexes:
    "tracks_pkey" PRIMARY KEY, btree (apple_id)
    "index_tracks_on_label" btree (label)

music_track_development=#

Und von der Rails-Konsole :

Loading development environment (Rails 4.2.1)
=> Unable to load pry
>> Track.primary_key
=> "apple_id"
>>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X