Ruby-on-rails 基于 2 列定义唯一的主键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12746280/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:50:35  来源:igfitidea点击:

Define a unique primary key based on 2 columns

ruby-on-railsprimary-keycomposite-primary-key

提问by Stéphane V

I would like to define a unique key for records based on 2 columns : 'id' and 'language'

我想为基于 2 列的记录定义一个唯一键:'id' 和 'language'

to let the user submits the following strings : id=1 language=en value=blabla english id=1 language=fr value=blabla french

让用户提交以下字符串:id=1 language=en value=blabla english id=1 language=fr value=blabla french

I tried to use set_primary_key and also add_index but it didn't work ( add_index :words, ["id", "language_id"], :unique => true )

我尝试使用 set_primary_key 和 add_index 但它没有用( add_index :words, ["id", "language_id"], :unique => true )

I have the following model :

我有以下型号:

class Word < ActiveRecord::Base
  belongs_to :dictionnary
  belongs_to :language

  attr_accessible :lang, :rev, :value, :dictionnary_id, :language_id

  validates :value, :uniqueness => true

end  

and this

和这个

class Language < ActiveRecord::Base
    has_many :words

    attr_accessible :lang
end

回答by rogal111

add_index :words, ["id", "language_id"], :unique => true

add_index :words, ["id", "language_id"], :unique => true

It should work. Maybe you have already some non-unique data in your db and index can't be created? But (as @Doon noticed it will be redundant since id is always unique). So you need create primary key on two columns.

它应该工作。也许您的数据库中已经有一些非唯一数据并且无法创建索引?但是(正如@Doon 注意到的那样,这将是多余的,因为 id 始终是唯一的)。所以你需要在两列上创建主键。

To define 2 column primary key in rails use:

要在 rails 中定义 2 列主键,请使用:

create_table :words, {:id => false} do |t|
  t.integer :id
  t.integer :language_id
  t.string :value
  t.timestamps
end
execute "ALTER TABLE words ADD PRIMARY KEY (id,language_id);"

And set primary_key in your model with this gem: http://rubygems.org/gems/composite_primary_keys:

并使用此 gem 在您的模型中设置 primary_key:http: //rubygems.org/gems/composite_primary_keys

class Word < ActiveRecord::Base
    self.primary_keys = :id,:language_id
end

回答by Vadim

In Rails 5 you can do the following:

在 Rails 5 中,您可以执行以下操作:

create_table :words, primary_key: %i[id language_id] do |t|
  t.integer :id
  t.integer :language_id
  t.string :value
  t.timestamps
end

It is also NOT necessary to set the primary_keyattribute on the Wordmodel.

也没有必要primary_keyWord模型上设置属性。

回答by Bhavnesh

Model

模型

class User < ActiveRecord::Base
  has_secure_password
  self.primary_keys = :name
end

Migration

移民

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :emailid
      t.string :password_digest
      t.integer :locked, :default => 0
      t.text :secretquestion
      t.string :answer

      t.timestamps null: false
    end
    add_index :users, :name, :unique => true
  end
end

You will get this table

你会得到这张桌子

image

图片

回答by Doon

As I said in my comments you will be fighting rails if you try this, and it isn't really supported out of the box. you can look at http://compositekeys.rubyforge.orgwhich offers a way to do composite primary keys in rails. I haven't used it, as I haven't had a need yet (normally when I have something that is composite key like it is just a join table with no primary key and a unique index on the joined pair (HABTM).

正如我在评论中所说的那样,如果您尝试此操作,您将与铁轨作斗争,并且它并不是开箱即用的。您可以查看http://compositekeys.rubyforge.org,它提供了一种在 Rails 中执行复合主键的方法。我还没有使用它,因为我还没有需要(通常当我有一些复合键时,比如它只是一个没有主键的连接表和连接对(HABTM)上的唯一索引。

回答by Michael

Depending on your use case you might want to try out composite key gemwhich allows you to define composite primary keys and also ehances ActiveRecord to deal with this kind of model (helps a lot for associations to this model or for url_for helpers etc.).

根据您的用例,您可能想要尝试复合键 gem,它允许您定义复合主键并增强 ActiveRecord 来处理这种模型(对于与此模型的关联或 url_for 助手等有很大帮助)。

So if you plan in using this model as any other rails model the gem will help a lot.

因此,如果您计划将此模型用作任何其他 Rails 模型,那么 gem 将有很大帮助。

回答by Sergio

I faced a similar problem when migrating a site to Rails. I had a table which stores text data for each language my site is available in so I had something like this:

将站点迁移到 Rails 时,我遇到了类似的问题。我有一个表格,用于存储我的网站可用的每种语言的文本数据,所以我有这样的事情:

CREATE TABLE Project_Lang(
    project_id INT NOT NULL,
    language_id INT NOT NULL,
    title VARCHAR(80),
    description TEXT,

    PRIMARY KEY pk_Project_Lang(project_id, language_id),

    FOREIGN KEY fk_Project_Lang_Project(project_id)
        REFERENCES Project(project_id)
        ON DELETE RESTRICT ON UPDATE CASCADE,

    FOREIGN KEY fk_Project_Lang_Language(language_id)
        REFERENCES Language(language_id)
        ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE = utf8_spanish_ci;

But since Rails doesn't handle composite primary keys out of the box I was forced to change the structure of the table so it had it's own primary key:

但是由于 Rails 不能开箱即用地处理复合主键,因此我被迫更改表的结构,以便它拥有自己的主键:

CREATE TABLE Project_Lang(
    project_lang_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    project_id INT NOT NULL,
    language_id INT NOT NULL,
    title VARCHAR(80),
    description TEXT,

    UNIQUE INDEX(project_id, language_id),

    FOREIGN KEY fk_Project_Lang_Project(project_id)
        REFERENCES Project(project_id)
        ON DELETE RESTRICT ON UPDATE CASCADE,

    FOREIGN KEY fk_Project_Lang_Language(language_id)
        REFERENCES Language(language_id)
        ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE = utf8_spanish_ci;

I also created a unique index for the columns that previously made the composite primary key so that no duplicate record is inserted. Then in my Rails model I could simply:

我还为之前构成复合主键的列创建了一个唯一索引,以便不会插入重复的记录。然后在我的 Rails 模型中,我可以简单地:

self.primary_key = "project_lang_id"

And that did the trick. Is not what I wanted but is better than fighting the framework.

这就是诀窍。不是我想要的,但比对抗框架要好。

回答by Son Tr.

Just like @rogal111 said, but if a primary key already exists then you'll want to do this

就像@rogal111 说的那样,但如果主键已经存在,那么你会想要这样做

ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key);