15

Mam następujące w moim pliku migracjiSzyny unikatowości i dopasowania db unikatowy indeks dla kolumny zerowej

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 

Chcę zapewnić, że jeśli product_id określona jest wyjątkowy, ale również chcę, aby umożliwić NULL tak mam następujący w moim modelu:

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

działa świetnie, ale mam następnie dodać indeks do pliku migracji

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

Oczywiście spowoduje to zgłoszenie wyjątku, gdy wstawiono dwie wartości puste dla id_produktu. Mogę po prostu pominąć indeks w migracji, ale jest szansa, że ​​dostanę dwa PaymentAgreements z tym samym product_id, jak pokazano tutaj: Concurrency and integrity

Moje pytanie brzmi, jaki jest najlepszy/najpowszechniejszy sposób radzenia sobie z tym problem

+0

To pytanie jest podobna do 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

Odpowiedz

0

Niektóre główne systemy baz danych nie zezwalają na unikalny indeks zawierający wiele wartości NULL: unikatowy dotyczy zarówno wartości NULL, jak i wartości innych niż NULL. Istnieją sposoby obejścia tego na poziomie bazy danych (np. Wyzwalacze lub kolumna obliczeniowa, patrz link text).

Można rozwiązać ten problem na poziomie aplikacji i wprowadzić sprawdzanie poprawności, które sprawdza unikalność, jeśli wartość product_id nie jest pusta.

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 

(Aktualizacja: Jak podkreślił zed_0xff, MySQL pozwala na wiele wartości null w unikalny indeks w najczęściej używanych silników składowania.)

11

to zależy od serwera db. jak mysql

indeks unikalny tworzy ograniczenie taki sposób, że wszystkie wartości indeksu muszą być różne. Wystąpił błąd, jeśli spróbujesz dodać nowy wiersz o wartości klucza , który pasuje do istniejącego wiersza. Ograniczenie nie ma zastosowania do wartości NULL , z wyjątkiem silnika BDB magazynującego . W przypadku innych silników indeks UNIQUE dopuszcza wiele wartości NULL dla kolumn , które mogą zawierać wartość NULL.

Powiązane problemy