我的迁移文件中有以下内容
def self.up
create_table :payment_agreements do |t|
t.boolean :automatic, :default => true, :null => false
t.string :payment_trigger_on_order
t.references :supplier
t.references :seller
t.references :product
t.timestamps
end
end
我想确保如果指定了product_id,它是唯一的,但我也想允许null,所以我的模型中有以下内容:
validates :product_id,
:uniqueness => true,
:allow_nil => true
效果很好,但我应该在迁移文件中添加一个索引
add_index :payment_agreements, :product_id, :unique => true
显然,当为product_id插入两个空值时,这将抛出异常。我可以简单地省略迁移中的索引,但之后我有可能获得两个PaymentAgreements,其中product_id与此处显示的相同:Concurrency and integrity
我的问题是处理这个问题的最佳/最常用方法是什么
答案 0 :(得分:11)
这取决于您的数据库服务器。 至于mysql:
UNIQUE索引创建约束 这样索引中的所有值都必须 与众不同。如果你发生错误 尝试添加具有键值的新行 与现有行匹配。这个 约束不适用于NULL 除BDB存储之外的值 发动机。对于其他引擎,一个独特的 index允许多个NULL值 可以包含NULL的列。
答案 1 :(得分:0)
某些主要数据库系统不允许唯一索引包含多个NULL:唯一适用于NULL和非NULL。在数据库级别上存在这种方法(例如,触发器或计算列;请参阅link text)。
您可以在应用程序级别解决此问题,并在product_id
不为空时进行验证以检查唯一性。
validate :enforce_unique_product_id
def enforce_unique_product_id
if (!self.product_id.nil? &&
PaymentAgreement.exists?(:conditions=>['product_id = ?', self.product_id]))
errors.add_to_base('There is already an agreement with product id " +
self.product_id)
end
end
(更新:正如zed_0xff所指出的,MySql允许在最常用的存储引擎中的UNIQUE索引中有多个NULL。)