2011-12-17 18 views
23

Chcę wprowadzić wyjątkowe ograniczenie w mojej jednostce Doctrine 2, tak aby name & test były unikatowe pod względem kolumny. ZnaczenieUnikalne ograniczenia w Doctrine 2, Symfony 2

  • obj1

    • Nazwa: nazwa1
    • Test: Test
  • obj2

    • Nazwa: name2
    • Test: Test < ---- powielane

ta powinna wywołać błąd jako próba jest powielany.

Próbowałem użyć ograniczenia unikalnego (Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity). Próbowaliśmy

* @UniqueEntity("name") 
* @UniqueEntity("test") 

i

* @UniqueEntity({"name", "test"}) 

Oba wydają się jedynym błędem wyzwalania kiedy mają zarówno nazwę i testu dublowane. na przykład.

  • obj1

    • Nazwa: nazwa1
    • Test: Test
  • obj2

    • Nazwa: name2
    • testu: test

Co to jest odpowiednia konfiguracja? A może gdzieś popełniłem błąd?

Może powinienem zawierać adnotację doktryny jak:

@Table(name="ecommerce_products",uniqueConstraints={@UniqueConstraint(name="search_idx", columns={"name", "email"})}) 

Ale to wciąż przyzwyczajenie uchwyt moja forma symfony walidacja myślę?

UPDATE

Mój kod testowy:

/** 
* @ORM\Entity 
* @ORM\Table(name="roles") 
* @UniqueEntity("name") 
* @UniqueEntity("test") 
*/ 
class Role { 

    /** 
    * @var integer 
    * @ORM\Column(type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue 
    */ 
    protected $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(type="string", length=32, unique=true) 
    * @Assert\MaxLength(32) 
    * @Assert\Regex("/^[a-zA-Z0-9_]+$/") 
    */ 
    protected $name; 

} 

$v = $this->get('validator'); 

$role = new Role(); 
$role->setName('jm'); 
$role->setTest('test'); 
$e = $v->validate($role); 
echo '=== 1 ==='; 
var_dump($e); 
if (count($e) == 0) 
    $em->persist($role);    

$role2 = new Role(); 
$role2->setName('john'); 
$role2->setTest('test'); 
$e = $v->validate($role2); 
echo '=== 2 ==='; 
var_dump($e); 
if (count($e) == 0) 
    $em->persist($role2); 

$em->flush(); 

Na pierwszym biegu (pusty tabeli):

=== 1 ===object(Symfony\Component\Validator\ConstraintViolationList)#322 (1) { 
    ["violations":protected]=> 
    array(0) { 
    } 
} 
=== 2 ===object(Symfony\Component\Validator\ConstraintViolationList)#289 (1) { 
    ["violations":protected]=> 
    array(0) { 
    } 
} 

Ale ja się błąd na warstwie bazy danych o UNIQUE. Więc jak powinienem pracować w warstwie sprawdzania poprawności?

+0

W drugim przykładzie, żadne z pól są duplikowane. To sprawia, że ​​twoje pytanie jest nieco niejasne. – greg0ire

+0

@ gre0ire, 'test' jest duplikowany? –

+0

Oops przepraszam. Ale wcześniej mówisz "Oboje". Więc o co chodzi z drugim przykładem? – greg0ire

Odpowiedz

49

te sprawdzają dla pól indywidualnie:

@UniqueEntity("name") 
@UniqueEntity("test") 

Oznacza to, że pierwszy z nich dostanie wyzwalane, gdy istnieje duplikat wartość name, natomiast drugi - gdy istnieje duplikat test wartości.

Jeśli chcesz walidacja nie kiedy zarównoname i test zawierają tę samą kombinację, należy użyć tego:

@UniqueEntity({"name", "test"}) 

o co chcesz pierwsze podejście powinno działać - chyba, że ​​zrobił coś złego gdzieś indziej. Spróbuj również wyczyścić pamięć podręczną, aby upewnić się, że to nie jest jego wina.

UPDATE

Co Zasugerowałem chodziło o część walidacji po stronie aplikacji. Jeśli wygenerowania schematu bazy danych za pomocą doktryny trzeba dostarczyć poziomu adnotacji Doktryna dla każdą kolumnę - jeśli chcesz aby były unikatowe niezależnie od siebie, oczywiście:

@Column(type = "string", unique = true) 
private $name; 

@Column(type = "string", unique = true) 
private $test; 

tych podejść dopełniacza siebie nawzajem - nie wykluczaj. @UniqueEntity zapewnia, że ​​duplikat nie dotrze nawet do warstwy bazy danych, a @Column zapewnia, że ​​jeśli to zrobi, warstwa bazy danych nie pozwoli mu przejść.

+0

Dziwne jest dla 'UniqueEntity', to nie działa! Występuje błąd tylko wtedy, gdy oba pola są duplikowane, zobacz moją aktualizację głównego pytania wkrótce –

+0

Jeśli chcę użyć '@ UniqueEntity', gdzie w moim kodzie powinienem umieścić? – Shawn

+0

@Shawn, w klasie encji. –

47

W opisie tabeli można również ustawić indeks dla wielu columns.

 
/** 
* @ORM\Entity 
* @ORM\Table(name="ecommerce_products",uniqueConstraints={ 
*  @ORM\UniqueConstraint(name="search_idx", columns={"name", "email"})}) 
*/ 

lub w formacie YAML:

Namespace\Entity\EntityName: 
    type: entity 
    table: ecommerce_products 
    uniqueConstraints: 
     uniqueConstraint: 
      columns: [name, email] 
+0

A kiedy pole jest relacją do innej tabeli? Podobnie jak 'private $ author'.Nie można umieścić autora ani autora w unikatowym. Jak mogę to rozwiązać? –

+0

@ hugomn, jeśli jest to zaplątane w element anotowany, możesz dodać: "myEntity_id". pytanie do @ -yoyer: jak dodać wiadomość o kostiumie? (lub jak uzyskać stronę z błędami?) – mboullouz

+0

@hugomn, myślę, że zdefiniowanie ograniczenia na podstawie kolumny sprzężonej nadal będzie działało. dawny. Biorąc pod uwagę, że masz zdefiniowany atrybut '@JoinColumn (name =" customer_id ", referencedColumnName =" id ")', określenie 'customer_id' w ograniczeniu powinno działać ... Domyślam się, że unikalne ograniczenie używa definicji z mysql nie php. Mam na myśli to, że unikalne ograniczenie powinno mieć nazwę kolumny mysql 'customer_id', a nie atrybut PHP' $ customer'. – yvoyer