15

Ho il seguente nel mio file di migrazioneRails vincolo di unicità e di corrispondenza indice univoco db per la colonna nullo

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 

voglio garantire che, se viene specificato un product_id è unico, ma voglio anche permettere nulla così ho il seguente nel mio modello:

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

Funziona grande, ma ho dovrebbe quindi aggiungere un indice per il file di migrazione

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

Ovviamente questo genera un'eccezione quando vengono inseriti due valori nulli per product_id. Potrei semplicemente omettere l'indice nella migrazione, ma c'è la possibilità che otterrò due Agevolazioni con lo stesso product_id come mostrato qui: Concurrency and integrity

La mia domanda è qual è il modo migliore/più comune per gestire questo problema

+0

Questa domanda è simile a 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

risposta

0

Alcuni importanti sistemi di database non consentono a un indice univoco di contenere più NULL: unico si applica a NULL e non NULL. Ci sono modi per aggirare questo a livello di database (ad esempio, trigger o una colonna calcolata, vedere link text).

È possibile risolvere questo problema a livello di applicazione e inserire una convalida che verifica l'univocità se lo product_id non è nullo.

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 

(Aggiornamento: Come sottolineato da zed_0xff, MySql consente a più NULL in un indice univoco nei motori di archiviazione più comunemente utilizzati.)

11

Dipende dal vostro db server. da per mysql:

un indice univoco crea un vincolo tale che tutti i valori dell'indice devono essere distinti. Si verifica un errore se si tenta di aggiungere una nuova riga con un valore chiave corrispondente a una riga esistente. Questo vincolo non si applica ai valori NULL tranne per il motore di memoria BDB . Per altri motori, un indice UNIQUE consente più valori NULL per le colonne che possono contenere NULL.