所以我有一张叫做投票的桌子。
有三列。 VoterID,VoteforID和投票。
每个列的唯一性并不重要,但同一行不能重复两次
例如。这是正确的
Voter_id | Votefor_id |表决
1 | 2 | 1
1 | 3 | 1
1 | 4 | 1
2 | 1 | 2
这是错误的。
Voter_id | Votefor_id |表决
1 | 2 | 1
1 | 2 | 1
1 | 4 | 1
2 | 1 | 2
目前,我在添加记录之前正在执行select语句,以确保不存在相同的行。当然,有一个更好的解决方案。
谢谢。
答案 0 :(得分:2)
使用uniqueness_validation上的scope
参数,例如:
validates :voter_id, uniqueness: { scope: :votefor_id }
范围参数可以是多个:
validates :voter_id, uniqueness: { scope: [:votefor_id, :vote] }
这实际上取决于细节,但对于手头的情况,我个人认为db约束在这里有点过分,因为竞争条件(documented in rails uniqueness validation)发生的可能性很低,因为我们需要
两个记录具有完全相同的voter_id,votefor_id和投票在同一时间提交(我们正在谈论毫秒),如果我可以假设一些关于OP业务逻辑voter
通常会是登录用户意味着重复的条目应该只来自他!!
我有很多使用uniqueness_validation
在生产中运行的rails应用程序就好了,只有one time它在一个具有许多同时条目的单个列的唯一性检查情况下失败了我(显然我那里需要db约束)。
如果数据完整性至关重要,您应该确保使用db约束。
或者如果你不介意开销&特别是如果您可以从(voter_id,votefor_id和投票)上的新索引中获益以提高搜索速度,我会说使用db约束。
否则我会说:保持简单并与uniquess_valdation
答案 1 :(得分:2)
如果数据完整性至关重要,则不应使用验证来保证唯一性。它可能会失败。保证唯一性的唯一方法是使用数据库约束。这是因为Rails validates_uniqueness
可以有竞争条件。
创建迁移以添加索引,或更改现有索引以反映此更改:
换新表:
class CreateVotes < ActiveRecord::Migration
def change
create_table :votes do |t|
t.belongs_to :voter
t.belongs_to :votefor
t.string :vote # Choose the correct column type
t.timestamps
end
add_index :votes, [:voter_id, :votefor_id, :vote], unique: true
end
end
对于现有表格:
class AddUniqueIndexToVotes < ActiveRecord::Migration
def change
add_index :votes, [voter_id, votefor_id, vote], unique: true
end
end
现在,如果您想向用户提供他们已经投票的反馈,您可以继续按照其他人的建议添加验证:
validates :voter_id, uniqueness: { scope: [:votefor_id, :vote] }
答案 2 :(得分:0)
在表定义中,添加UNIQUE
表约束:
CREATE TABLE votes (
voter_id int NOT NULL,
votefor_id int NOT NULL,
vote int NOT NULL,
UNIQUE (voter_id, votefor_id, vote)
);
这样PostgreSQL会检查重复项。如果您尝试INSERT
一条记录,其值对于所有三列都与现有记录中的值相同,则会引发错误。