【问题标题】:Validate uniquness in ActiveRecord on part of a string在部分字符串上验证 ActiveRecord 中的唯一性
【发布时间】:2016-06-21 17:11:55
【问题描述】:

假设我在Dummy 模型上有registration_id 属性。 它的数据类型是字符串。 它的长度可以是 10-14 个字符,但我想对 仅在最后 10 个字符进行唯一性验证。 (奇怪但真实)

现在我该如何实现呢?

我想到的:

  1. Dummy 表中创建另一个属性last_ten_chars_registration_id 以保存最后10 个字符,并为该属性设置唯一性。 (因为计算属性显然不适用于唯一性验证)

  2. 我可以创建自定义验证器并编写查询。 我不确定(可能是like查询)

谁能建议我更好的方法来实现这一点?

【问题讨论】:

  • 我喜欢last_ten_chars_registration_id 的想法。并且您可以索引该列以在这些唯一性查询上获得良好的性能。数据库性能并不完全是我的驾驶室,但我想like 查询不会随着时间的推移和增长而变得如此高效。
  • 不是完全不同意,而是规范化而不是优化。除非有理由进行优化,例如数百万条记录或慢查询,否则我仍然认为 LIKE 检查更好。如果您有两列具有相同的数据,那么您如何确定它永远不会不同步,保持它们匹配将需要其他地方的额外逻辑。自定义验证强制执行业务逻辑,即您不能有两条具有相同最后 10 个字符的 reg ID 的记录。

标签: ruby-on-rails validation ruby-on-rails-4 activerecord postgresql-9.1


【解决方案1】:

您可以使用这样的自定义验证器。

class Dummy < ActiveRecord::Base
  validates_with RegistrationValidator, :fields => [:registration_id]

  # Whatever else...
end

class RegistrationValidator < ActiveModel::Validator
  def validate(record)
    reg_id = record.registration_id.last(10).join
    if Dummy.where('registration_id LIKE ?',"%#{reg_id}")
      record.errors[:registration_id] << "Registration ID taken!"
    end
  end
end

【讨论】:

  • 修复了 record.registration_id 中的一个错字。
【解决方案2】:

与 GoGoCarl 相同,我也认为这在很大程度上取决于您需要的性能。我认为自定义查询(不使用LIKE,而是使用RIGHT(registration_id, 10) 函数,至少在MySQL 中)会很好,除非Dummy 表很大或者您需要查询超快。在这种情况下,我也会使用最后 10 个字符和随附的数据库索引来创建特殊列。

一个务实的解决方案可能是首先采用自定义查询路线,因为它对我来说实施起来似乎更简单,然后,如果性能开始受到影响,则切换到特殊列。

您也可以进行自己的基准测试,例如使用您期望的记录数填充测试Dummy 表,并亲自查看性能是否适合您。

另请参阅related SO question,了解解决方案相似的字符串 SQL 函数性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 2021-11-13
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多