15

je suit dans mon dossier de migrationRails __gVirt_NP_NN_NNPS<__ contrainte d'unicité et correspondant à index unique db pour la colonne null

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 

Je veux faire en sorte que si un product_id est spécifié, il est unique, mais je veux aussi permettre ainsi null Je suit dans mon modèle:

validates :product_id, 
      :uniqueness => true, 
      :allow_nil => true 

Fonctionne très bien mais je puis ajouter un index dans le fichier de migration

add_index :payment_agreements, :product_id, :unique => true 

Évidemment, cela va générer une exception lorsque deux valeurs nulles sont insérées pour product_id. Je pourrais simplement omettre l'index dans la migration, mais il y a une chance que j'obtienne deux PaymentAgreements avec le même product_id comme montré ici: Concurrency and integrity

Ma question est quelle est la meilleure/la plus courante pour faire face à cela problème

+0

Cette question est similaire à http://stackoverflow.com/questions/191421/how-to-create-a-unique-index-on-a-null-column – x1a4

+1

validates_uniqueness_of: product_id,: if = > lambda {! self.product_id.nil? } – user386660

Répondre

0

Certains systèmes de base de données principaux ne permettent pas un index unique pour contenir plusieurs valeurs NULL: unique s'applique aux valeurs NULL ainsi qu'aux non-NULL. Il existe des moyens de contourner cela au niveau de la base de données (par exemple, des déclencheurs ou une colonne calculée, voir link text).

Vous pouvez résoudre ce problème au niveau de l'application et mettre en place une validation qui vérifie l'unicité si le product_id n'est pas nul.

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 

(Mise à jour: Comme l'a souligné zed_0xff, MySql permet à plusieurs NULLs dans un index unique dans les moteurs de stockage les plus couramment utilisés.)

11

cela dépend de votre serveur db. que pour MySQL:

Un index unique crée une contrainte telle que toutes les valeurs de l'indice doivent être distincts. Une erreur se produit si vous essayez d'ajouter une nouvelle ligne avec une valeur de clé qui correspond à une ligne existante. Cette contrainte ne s'applique pas aux valeurs NULL à l'exception du moteur de stockage BDB . Pour les autres moteurs, , un index UNIQUE autorise plusieurs valeurs NULL pour les colonnes pouvant contenir NULL.