16

我的迁移文件中有以下内容

  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 插入两个空值时,这将引发异常。我可以简单地省略迁移中的索引,但是我有可能得到两个具有相同 product_id 的 PaymentAgreements,如下所示:并发性和完整性

我的问题是处理这个问题的最好/最常见的方法是什么

4

2 回答 2

11

it depends on your db server. as for mysql:

A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. This constraint does not apply to NULL values except for the BDB storage engine. For other engines, a UNIQUE index allows multiple NULL values for columns that can contain NULL.

于 2010-05-28T07:16:57.370 回答
0

一些主要的数据库系统不允许唯一索引包含多个 NULL:唯一适用于 NULL 以及非 NULL。在数据库级别有解决此问题的方法(例如,触发器或计算列;请参阅链接文本)。

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 允许在最常用的存储引擎中的唯一索引中存在多个 NULL。)

于 2010-05-28T05:38:48.687 回答