为了账号安全,请及时绑定邮箱和手机立即绑定

使用Rails,如何将主键设置为不是整数类型的列?

/ 猿问

使用Rails,如何将主键设置为不是整数类型的列?

胡子哥哥 2019-08-16 15:54:57

使用Rails,如何将主键设置为不是整数类型的列?

我正在使用Rails迁移来管理数据库模式,我正在创建一个简单的表,我希望使用非整数值作为主键(特别是字符串)。为了从我的问题中抽象出来,让我们说有一个表格employees,其中员工用字母数字字符串标识,例如"134SNW"

我试过在这样的迁移中创建表:

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

这给了我什么似乎完全忽略了这条线t.string :emp_id并继续前进并使它成为一个整数列。有没有其他方法让rails为我生成PRIMARY_KEY约束(我正在使用PostgreSQL),而不必在execute调用中编写SQL ?

注意:我知道最好不要使用字符串列作为主键,所以请不要回答只是说添加一个整数主键。无论如何我可以添加一个,但这个问题仍然有效。


查看完整描述

3 回答

?
互换的青春

我有一种处理方式。执行的SQL是ANSI SQL,因此它可能适用于大多数符合ANSI SQL的关系数据库。我测试过这适用于MySQL。

移民:

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

在你的模型中这样做:

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


查看完整回答
反对 回复 2019-08-16
?
手掌心

不幸的是,我已经确定不使用它就不可能做到这一点execute

为什么它不起作用

通过检查ActiveRecord源,我们可以找到以下代码create_table

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

因此,我们可以看到,当您尝试在create_table选项中指定主键时,它会创建具有指定名称的主键(或者,如果未指定,则创建id)。它通过调用您可以在表定义块中使用的相同方法来完成此操作:primary_key

schema_statements.rb

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_nameendexecute "ALTER TABLE employees ADD PRIMARY KEY (emp_id);"

正如Sean McCleary所提到的,您的ActiveRecord模型应该使用set_primary_key以下方法设置主键:

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


查看完整回答
反对 回复 2019-08-16
?
慕田峪7331174

这有效:


create_table :employees, :primary_key => :emp_id do |t|

  t.string :first_name

  t.string :last_name

end

change_column :employees, :emp_id, :string

它可能不是很漂亮,但最终的结果正是你想要的。


查看完整回答
反对 回复 2019-08-16

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信