저는 Rails 마이그레이션을 사용하여 데이터베이스 스키마를 관리하고 있으며 정수가 아닌 값을 기본 키 (특히 문자열)로 사용하려는 간단한 테이블을 만들고 있습니다. 내 문제를 추상화하기 위해 employees
직원이 영숫자 문자열로 식별되는 테이블이 있다고 가정 해 보겠습니다 "134SNW"
.
다음과 같은 마이그레이션에서 테이블을 만들려고했습니다.
create_table :employees, {:primary_key => :emp_id} do |t|
t.string :emp_id
t.string :first_name
t.string :last_name
end
이것이 나에게주는 것은 라인을 완전히 무시하고 t.string :emp_id
정수 열로 만든 것처럼 보입니다 . execute
호출 에서 SQL을 작성하지 않고도 레일이 PRIMARY_KEY 제약 조건 (PostgreSQL을 사용하고 있음)을 생성하도록하는 다른 방법이 있습니까?
참고 : 문자열 열을 기본 키로 사용하는 것이 최선이 아니라는 것을 알고 있으므로 정수 기본 키를 추가하라는 대답은하지 마십시오. 어쨌든 하나를 추가 할 수 있지만이 질문은 여전히 유효합니다.
답변
불행히도 .NET을 사용하지 않고는 할 수 없다고 판단했습니다 execute
.
작동하지 않는 이유
ActiveRecord 소스를 조사하여 다음에 대한 코드를 찾을 수 있습니다 create_table
.
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
따라서 create_table
옵션 에서 기본 키를 지정하려고하면 지정된 이름으로 기본 키가 생성된다는 것을 알 수 있습니다 (또는 지정되지 않은 경우 id
). 테이블 정의 블록 내에서 사용할 수있는 것과 동일한 메서드를 호출하여이를 수행합니다 primary_key
..
def primary_key(name)
column(name, :primary_key)
end
이것은 지정된 유형의 이름을 가진 열을 생성합니다 :primary_key
. 이는 표준 데이터베이스 어댑터에서 다음과 같이 설정됩니다.
PostgreSQL: "serial primary key"
MySQL: "int(11) DEFAULT NULL auto_increment PRIMARY KEY"
SQLite: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"
해결 방법
우리는 이것들을 기본 키 유형으로 사용 execute
하기 때문에 정수가 아닌 기본 키를 만들어야합니다 (PostgreSQL serial
은 시퀀스를 사용하는 정수입니다).
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);"
로 그리고 숀 McCleary 언급 , 당신의 액티브 모델을 사용하여 기본 키를 설정해야합니다 set_primary_key
:
class Employee < ActiveRecord::Base
set_primary_key :emp_id
...
end
답변
이것은 작동합니다 :
create_table :employees, :primary_key => :emp_id do |t|
t.string :first_name
t.string :last_name
end
change_column :employees, :emp_id, :string
예쁘지 않을 수도 있지만 최종 결과는 정확히 원하는 것입니다.
답변
나는 이것을 처리하는 한 가지 방법이 있습니다. 실행 된 SQL은 ANSI SQL이므로 대부분의 ANSI SQL 호환 관계형 데이터베이스에서 작동합니다. 이것이 MySQL에서 작동하는지 테스트했습니다.
이주:
create_table :users, :id => false do |t|
t.string :oid, :limit => 10, :null => false
...
end
execute "ALTER TABLE users ADD PRIMARY KEY (oid);"
모델에서 다음을 수행하십시오.
class User < ActiveRecord::Base
set_primary_key :oid
...
end
답변
Rails 4.2에서 시도했습니다. 사용자 지정 기본 키를 추가하려면 마이그레이션을 다음과 같이 작성할 수 있습니다.
# 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
문서를보고 column(name, type, options = {})
다음 행을 읽으십시오.
type
: primary_key와, : : 문자열, 텍스트, : 정수 : 플로트 : 진수 : 날짜 : 시간 : 날짜 : 이진 : 매개 변수는 일반적으로 마이그레이션 기본 다음 중 하나입니다 유형 중 하나입니다 부울 .
내가 보여준 것처럼 위의 ides를 얻었습니다. 이 마이그레이션을 실행 한 후의 테이블 메타 데이터는 다음과 같습니다.
[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=#
그리고 Rails 콘솔에서 :
Loading development environment (Rails 4.2.1)
=> Unable to load pry
>> Track.primary_key
=> "apple_id"
>>
답변
Rails 5에서 할 수있는 일은
create_table :employees, id: :string do |t|
t.string :first_name
t.string :last_name
end
create_table 문서를 참조하십시오 .
답변
이 방법을 사용하여 수행 할 수있는 것 같습니다.
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
그러면 widget_id 열이 Widget 클래스의 기본 키가되고 개체가 생성 될 때 필드를 채우는 것은 사용자의 몫입니다. before create 콜백을 사용하면 가능합니다.
그래서 라인을 따라 뭔가
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
답변
저는 Rails 2.3.5를 사용하고 있으며 다음 방법은 SQLite3에서 작동합니다.
create_table :widgets, { :primary_key => :widget_id } do |t|
t.string :widget_id
# other column definitions
end
: id => false는 필요하지 않습니다.