如何使用 Rails 在数据库中添加复合主键?
How to add composite primary keys in db using Rails?
我正在使用 Rails 5.0 和 Postgresql 9.5
我需要将复合主键添加到我的模型 'User_achievement'(添加到 link 'User' 和 'Achievement' 模型,您可能猜到了)。
所以我尝试使用 "composite_primary_keys" gem。我按照所有说明进行操作,然而,结果并不像我预期的那样。根据 psql 工具的信息,它似乎没有在 'user_achievement' table 中创建 pkey:
test1_development=> \d user_achievements
Table "public.user_achievements"
Column | Type | Modifiers
----------------+---------+-----------
user_id | integer |
achievement_id | integer |
uach_date | date |
Indexes:
"index_user_achievements_on_achievement_id" btree (achievement_id)
"index_user_achievements_on_user_id" btree (user_id)
Foreign-key constraints:
"fk_rails_4efde02858" FOREIGN KEY (user_id) REFERENCES users(id)
"fk_rails_c44f5b3b25" FOREIGN KEY (achievement_id) REFERENCES achievements(id)
这是模型和迁移的代码:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
end
end
end
class CreateAchievements < ActiveRecord::Migration[5.0]
def change
create_table :achievements do |t|
t.string :ach_name
t.text :ach_desc
end
end
end
class CreateUserAchievements < ActiveRecord::Migration[5.0]
def change
create_table :user_achievements, id: false do |t|
t.belongs_to :user, :foreign_key => [:id]
t.belongs_to :achievement, :foreign_key => [:id]
t.date :uach_date
end
end
end
class Achievement < ApplicationRecord
has_many :user_achievements
end
class User < ApplicationRecord
has_many :user_achievements
end
class UserAchievement < ApplicationRecord
self.primary_keys = :user_id, :achievement_id
belongs_to :user, :foreign_key => [:id]
belongs_to :achievement, :foreign_key => [:id]
end
那么 gem 应该改变数据库 table 吗?或者它只影响 rails' 环境?
是否有改变数据库的唯一方法 - 在迁移中添加 execute 行?
既然没有人发布任何有用的东西,我现在就分享一下。
Gem 'composite_primary_key' (CPK) 不会更改数据库中的任何内容,因此如果您仍然需要它 - 您应该手动执行(将命令添加到迁移)。
CPK 唯一做的就是用 'understanding' 扩展 Rails 复合主键是什么,因为它最初没有并显示错误。
无论如何,我发现在 Rails 应用程序中使用复合主键是非常复杂和有问题的,因为它使得使用其他 gems 非常紧张(每一个新的 gem 安装你请记住,某些地方可能会出错)以及将来使用 cpks 更改代码。它还使不熟悉此功能的其他人更难理解您的代码。所以你应该总是指定你已经使用了CPK。
一个很好的替代方法是添加一个带有 'unique' 选项的索引,这在技术上意味着完全相同,但不需要额外的麻烦。
所以只有在确实需要时才使用它,而且没有其他不那么复杂的解决方案!
我正在使用 Rails 5.0 和 Postgresql 9.5
我需要将复合主键添加到我的模型 'User_achievement'(添加到 link 'User' 和 'Achievement' 模型,您可能猜到了)。
所以我尝试使用 "composite_primary_keys" gem。我按照所有说明进行操作,然而,结果并不像我预期的那样。根据 psql 工具的信息,它似乎没有在 'user_achievement' table 中创建 pkey:
test1_development=> \d user_achievements
Table "public.user_achievements"
Column | Type | Modifiers
----------------+---------+-----------
user_id | integer |
achievement_id | integer |
uach_date | date |
Indexes:
"index_user_achievements_on_achievement_id" btree (achievement_id)
"index_user_achievements_on_user_id" btree (user_id)
Foreign-key constraints:
"fk_rails_4efde02858" FOREIGN KEY (user_id) REFERENCES users(id)
"fk_rails_c44f5b3b25" FOREIGN KEY (achievement_id) REFERENCES achievements(id)
这是模型和迁移的代码:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
end
end
end
class CreateAchievements < ActiveRecord::Migration[5.0]
def change
create_table :achievements do |t|
t.string :ach_name
t.text :ach_desc
end
end
end
class CreateUserAchievements < ActiveRecord::Migration[5.0]
def change
create_table :user_achievements, id: false do |t|
t.belongs_to :user, :foreign_key => [:id]
t.belongs_to :achievement, :foreign_key => [:id]
t.date :uach_date
end
end
end
class Achievement < ApplicationRecord
has_many :user_achievements
end
class User < ApplicationRecord
has_many :user_achievements
end
class UserAchievement < ApplicationRecord
self.primary_keys = :user_id, :achievement_id
belongs_to :user, :foreign_key => [:id]
belongs_to :achievement, :foreign_key => [:id]
end
那么 gem 应该改变数据库 table 吗?或者它只影响 rails' 环境? 是否有改变数据库的唯一方法 - 在迁移中添加 execute 行?
既然没有人发布任何有用的东西,我现在就分享一下。
Gem 'composite_primary_key' (CPK) 不会更改数据库中的任何内容,因此如果您仍然需要它 - 您应该手动执行(将命令添加到迁移)。
CPK 唯一做的就是用 'understanding' 扩展 Rails 复合主键是什么,因为它最初没有并显示错误。
无论如何,我发现在 Rails 应用程序中使用复合主键是非常复杂和有问题的,因为它使得使用其他 gems 非常紧张(每一个新的 gem 安装你请记住,某些地方可能会出错)以及将来使用 cpks 更改代码。它还使不熟悉此功能的其他人更难理解您的代码。所以你应该总是指定你已经使用了CPK。
一个很好的替代方法是添加一个带有 'unique' 选项的索引,这在技术上意味着完全相同,但不需要额外的麻烦。
所以只有在确实需要时才使用它,而且没有其他不那么复杂的解决方案!