在连接表中,Rails 的最佳解决方法是什么? 缺少组合键?
create_table :categories_posts, :id => false do |t|
t.column :category_id, :integer, :null => false
t.column :post_id, :integer, :null => false
end
我有一个连接表(如上所述),其中的列引用相应的categories表和posts表。 我想对categories_posts连接表中的复合键category_id, post_id强制执行唯一约束。 但 Rails 不支持这一点(我相信)。
为了避免数据中可能出现具有相同的category_id 和 post_id 组合的重复行,Rails 中缺少复合键的最佳解决方法是什么?
我的假设是:
- 默认的自动编号列 (id:integer) 不会做任何事情 在这种情况下保护我的数据。
- ActiveScaffold 可以提供 解决方案,但我不确定是否 将它包含在我的中有点过分了 项目只是为了这个单曲 功能,特别是如果有 更优雅的答案。
create_table :categories_posts, :id => false do |t|
t.column :category_id, :integer, :null => false
t.column :post_id, :integer, :null => false
end
I have a join table (as above) with columns that refer to a corresponding categories table and a posts table. I wanted to enforce a unique constraint on the composite key category_id, post_id in the categories_posts join table. But Rails does not support this (I believe).
To avoid the potential for duplicate rows in my data having the same combination of category_id and post_id, what's the best workaround for the absence of a composite key in Rails?
My assumptions here are:
- The default auto-number column
(id:integer) would do nothing to
protect my data in this situation. - ActiveScaffold may provide a
solution but I'm not sure if
it's overkill to include it in my
project simply for this single
feature, especially if there is a
more elegant answer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
添加包含两列的唯一索引。 这将阻止您插入包含重复的category_id/post_id 对的记录。
Add a unique index that includes both columns. That will prevent you from inserting a record that contains a duplicate category_id/post_id pair.
推荐“正确”的方法非常困难。
1) 务实的方法
使用验证器并且不添加唯一的复合索引。 这会在用户界面中为您提供漂亮的消息,而且它确实有效。
您还可以在连接表中添加两个单独的索引来加快搜索速度:
请注意(根据Rails 3 Way一书),验证并不是万无一失的,因为之间存在潜在的竞争条件。 SELECT 和 INSERT/UPDATE 查询。 如果您必须绝对确定不存在重复记录,建议使用唯一约束。
2) 防弹方法
在这种方法中,我们希望在数据库级别施加约束。 所以这意味着创建复合索引:
最大的优点是数据库完整性很好,缺点是向用户报告没有太多有用的错误。 请注意,在创建复合索引时,列的顺序很重要。
如果将选择性较少的列作为索引中的前导列,并将选择性最多的列放在末尾,则对非前导索引列有条件的其他查询也可以利用 INDEX SKIP SCAN。 您可能需要再添加一个索引才能利用它们,但这高度依赖于数据库。
3) 两者的组合
人们可以阅读有关两者的组合的内容,但我倾向于只喜欢第一个。
It's very hard to recommend the "right" approach.
1) The pragmatic approach
Use validator and do not add unique composite index. This gives you nice messages in the UI and it just works.
You can also add two separate indexes in your join tables to speed up searches:
Please note (according to the book Rails 3 Way) the validation is not foolproof because of a potential race condition between the SELECT and INSERT/UPDATE queries. It is recommended to use unique constraint if you must be absolutely sure there are no duplicate records.
2) The bulletproof approach
In this approach we want to put a constraint on the database level. So it means to create a composite index:
Big advantage is a great database integrity, disadvantage is not much useful error reporting to the user. Please note in creating of composite index, order of columns is important.
If you put less selective columns as leading columns in index and put most selective columns at the end, other queries which have condition on non-leading index columns may also take advantage of INDEX SKIP SCAN. You may need to add one more index to get advantage of them, but this is highly database dependant.
3) Combination of both
One can read about combination of both, but I tend to like the number one only.
我认为您可以更轻松地验证其中一个字段的唯一性,并将另一个字段作为范围:
从 API:
验证指定属性的值在整个系统中是否唯一。 对于确保只有一个用户可以命名为“davidhh”很有用。
它还可以根据多个范围参数验证指定属性的值是否唯一。 例如,确保教师每学期只能在特定课程的时间表上出现一次。
创建记录时,将执行检查以确保数据库中不存在具有指定属性(映射到列)的给定值的记录。 当记录更新时,会进行相同的检查,但忽略记录本身。
配置选项:
I think you can find easier to validate uniqueness of one of the fields with the other as a scope:
FROM THE API:
Validates whether the value of the specified attributes are unique across the system. Useful for making sure that only one user can be named "davidhh".
It can also validate whether the value of the specified attributes are unique based on multiple scope parameters. For example, making sure that a teacher can only be on the schedule once per semester for a particular class.
When the record is created, a check is performed to make sure that no record exists in the database with the given value for the specified attribute (that maps to a column). When the record is updated, the same check is made but disregarding the record itself.
Configuration options:
当我在 Rails 中遇到此问题时,我会实现以下两项:
1) 您应该在数据库级别声明一个唯一的复合索引,以确保 dbms 不会创建重复的记录。
2) 为了提供比上面更平滑的错误消息,请向 Rails 模型添加验证:
I implement both of the following when I have this issue in rails:
1) You should have a unique composite index declared at the database level to ensure that the dbms won't let a duplicate record get created.
2) To provide smoother error msgs than just the above, add a validation to the Rails model:
解决方案可以是在模型中添加索引和验证。
所以在迁移中你有:
add_index :categories_posts, [:category_id, :post_id], :unique => true
在模型中:
validates_uniqueness_of :category_id, :scope => [:category_id,:post_id]
validates_uniqueness_of :post_id, :scope => [:category_id,:post_id]
A solution can be to add both the index and validation in the model.
So in the migration you have:
add_index :categories_posts, [:category_id, :post_id], :unique => true
And in the model:
validates_uniqueness_of :category_id, :scope => [:category_id, :post_id]
validates_uniqueness_of :post_id, :scope => [:category_id, :post_id]