web-dev-qa-db-ja.com

Doctrine 2、Symfony 2の一意の制約

私はDoctrine 2エンティティでnametestが列ごとに一意であるように一意の制約を作成します。

  • obj1

    • 名前:name1
    • テスト:テスト
  • obj2

    • 名前:name2
    • テスト:テスト<----重複

テストが複製されると、エラーが発生します。

一意の制約(Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity)。試した

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

そして

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

両方とも、名前とテストの両方が重複している場合にのみエラーをトリガーするようです。例えば。

  • obj1

    • 名前:name1
    • テスト:テスト
  • obj2

    • 名前:name2
    • テスト:テスト

適切なセットアップは何ですか?それとも、どこかでミスをしたかもしれませんか?

おそらくdoctrineアノテーションを含める必要があります:

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

しかし、それでもsymfonyのフォーム検証を処理できないと思いますか?

[〜#〜] update [〜#〜]

私のテストコード:

/**
 * @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();

最初の実行時(空のテーブル):

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

ただし、データベース層で一意制約に関するエラーが発生します。では、検証レイヤーをどのように動作させる必要がありますか?

29
Jiew Meng

これらはフィールドを個別にチェックします。

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

つまり、最初の1つはname値が重複するときにトリガーされ、2つ目はtest値が重複するときにトリガーされます。

bothnametestが同じcombinationを含むときに検証を失敗させる場合、これを使用します:

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

あなたが望むもののために、最初のアプローチはうまくいくはずです-あなたが他のどこかで間違ったことをしない限り。また、キャッシュをクリアして、障害ではないことを確認してください。

[〜#〜] update [〜#〜]

私が提案したのは、アプリ側の検証部分についてでした。 Doctrineを使用してデータベーススキーマを生成する場合、each列にDoctrineレベルアノテーションを提供する必要があります—それらを作成する場合もちろん、互いに独立して一意です:

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

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

これらのアプローチは互いに補完するものであり、排除するものではありません。 @UniqueEntityは、複製がデータベース層に到達しないことを確認しますが、@Columnは、もしそうなら、データベース層が通過させないことを保証します。

50

テーブルアノテーションでは、複数の のインデックスを設定することもできます。

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

またはYAML形式の場合:

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