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.

8voto

paulthenerd Punkte 9482

Es sieht so aus, als ob dies mit diesem Ansatz möglich wäre:

create_table :widgets, :id => false do |t|
  t.string :widget_id, :limit => 20, :primary => true

  # other column definitions
end

class Widget < ActiveRecord::Base
  set_primary_key "widget_id"
end

Dadurch wird die Spalte widget_id zum Primärschlüssel für die Widget-Klasse, und es liegt dann an Ihnen, das Feld bei der Erstellung von Objekten zu füllen. Sie sollten in der Lage sein, dies zu tun, indem Sie den Before-Create-Callback verwenden.

Also etwas in der Größenordnung von

class Widget < ActiveRecord::Base
  set_primary_key "widget_id"

  before_create :init_widget_id

  private
  def init_widget_id
    self.widget_id = generate_widget_id
    # generate_widget_id represents whatever logic you are using to generate a unique id
  end
end

8voto

Trung LE Punkte 81

Ich bin auf Rails 2.3.5 und mein folgender Weg funktioniert mit SQLite3

create_table :widgets, { :primary_key => :widget_id } do |t|
  t.string :widget_id

  # other column definitions
end

Es besteht keine Notwendigkeit für :id => false.

4voto

Giles Bowkett Punkte 529

Nach fast jeder Lösung, die besagt "das hat bei mir mit Datenbank X funktioniert", sehe ich einen Kommentar des ursprünglichen Posters, der besagt "hat bei mir mit Postgres nicht funktioniert". Das eigentliche Problem hier könnte tatsächlich die Postgres-Unterstützung in Rails sein, die nicht fehlerfrei ist und wahrscheinlich 2009, als diese Frage ursprünglich gestellt wurde, noch schlechter war. Wenn ich mich zum Beispiel richtig erinnere, kann man mit Postgres keine brauchbare Ausgabe von rake db:schema:dump .

Ich bin selbst kein Postgres-Ninja, ich habe diese Informationen aus Xavier Shays hervorragendem PeepCode-Video über Postgres. Das Video übersieht eigentlich eine Bibliothek von Aaron Patterson, ich glaube Texticle, aber ich könnte mich auch irren. Aber abgesehen davon ist es ziemlich großartig.

Wie auch immer, wenn Sie dieses Problem mit Postgres haben, schauen Sie, ob die Lösungen in anderen Datenbanken funktionieren. Verwenden Sie vielleicht rails new um eine neue Anwendung als Sandbox zu erstellen, oder erstellen Sie einfach etwas wie

sandbox:
  adapter: sqlite3
  database: db/sandbox.sqlite3
  pool: 5
  timeout: 5000

en config/database.yml .

Und wenn Sie feststellen können, dass es sich um ein Postgres-Support-Problem handelt und Sie eine Lösung finden, tragen Sie bitte Patches zu Rails bei oder packen Sie Ihre Korrekturen in ein Gem, denn die Postgres-Benutzerbasis innerhalb der Rails-Community ist ziemlich groß, vor allem dank Heroku.

4voto

shicholas Punkte 6033

Ich habe eine Lösung für dieses Problem gefunden, die mit Rails 3 funktioniert:

Die Migrationsdatei:

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

Und in dem Modell employee.rb:

self.primary_key = :emp_id

3voto

Clark Punkte 31

Der Trick, der bei mir mit Rails 3 und MySQL funktioniert hat, war folgender:

create_table :events, {:id => false} do |t|
  t.string :id, :null => false
end

add_index :events, :id, :unique => true

Also:

  1. :id => false verwenden, um keinen Integer-Primärschlüssel zu erzeugen
  2. den gewünschten Datentyp verwenden, und :null => false hinzufügen
  3. einen eindeutigen Index für diese Spalte hinzufügen

Es scheint, dass MySQL den eindeutigen Index einer Nicht-Null-Spalte in einen Primärschlüssel umwandelt!

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