Development Tip

교리 2 연관성을 통한 상속 매핑

yourdevel 2021. 1. 7. 20:07
반응형

교리 2 연관성을 통한 상속 매핑


참고 : 내가 원하는 것이 불가능한 경우 "불가능"응답이 허용됩니다.

대한 교리 2 문서 상속 매핑 , 그것은 2 가지 방법이 있습니다 말한다 :

  • 단일 테이블 상속 (STI)
  • CTI (클래스 테이블 상속)

둘 다 경고가 있습니다.

STI / CTI 엔터티를 다 대일 또는 일대일 엔터티로 사용 하는 경우 상속 계층 의 상위 수준 에있는 클래스 중 하나 를 "targetEntity"로 사용해서는 안되며 하위 클래스가없는 클래스 만 사용해야합니다. 그렇지 않으면 Doctrine은이 엔티티의 프록시 인스턴스를 생성 할 수 없으며 항상 엔티티를 열심히로드합니다.

그렇다면 기본 (추상) 클래스에 대한 연결과 함께 상속을 계속 사용할있습니까? (물론 성능 유지)


사용자가 여러 개를 가지고 있습니다 Pet( Dog또는로 확장 된 추상 클래스 Cat).

내가하고 싶은 것 :

class User {
    /**
     * @var array(Pet) (array of Dog or Cat)
     */
    private $pets;
}

교리 문서의 경고 때문에 다음과 같이해야합니다.

class User {
    /**
     * @var array(Dog)
     */
    private $dogs;
    /**
     * @var array(Cat)
     */
    private $cats;
}

상속의 이점을 잃어 버리기 때문에 이것은 성가신 일입니다!

참고 : DB 매핑에 대한 Doctrine 주석을 추가하지 않았지만 의미를 이해할 수 있습니다.


나는 피곤하지만 이것은 아무것도에 대해 많은 고뇌처럼 보입니다.

그 경고의 중요한 부분을 놓쳤습니다.

STI / CTI 엔티티 를 다 대일 또는 일대일 엔티티 사용하는 경우

귀하의 예에서는 그렇지 않습니다! 교리 주석을 생략하지 않았다면 눈치 채 셨을 것입니다.

User :: pets 연관은 [One | Many] ToOne이 아니라 OneToMany입니다. 한 명의 사용자가 많은 애완 동물을 가지고 있습니다.

역 연관 OneToOne이지만 상속이없는 사용자를 대상으로합니다.

Robin의 대답은 좋은 힌트 여야합니다. SQL 쿼리를 기록하고 교리가 실제로 데이터베이스에 어떤 영향을 미치는지 확인할 수 있습니다!


성능 저하 시나리오는 다음과 같습니다.

abstract class Pet { ... }

class Cat extends Pet { ... } 

class Dog extends Pet { ... }

class Collar {
   /**
    * @Column(length="16")
    */

   protected $color;
   /**
    * ManyToOne(targetEntity="Pet")
    */
   protected $owner;
}

이제 모든 블루 칼라를 반복하고 싶다면 Doctrine은 문제가 발생합니다. $ owner가 어떤 클래스가 될지 모르기 때문에 Proxy를 사용할 수 없습니다. 대신 $ owner를 열심히로드하여 고양이인지 개인 지 알아 내야합니다.

This isn't a problem for OneToMany or ManyToMany relationships, because in that case, lazy loading works fine. Instead of a proxy, you get a PersistentCollection. And a PersistentCollection is always just a PersistentCollection. It doesn't care about it's own contents until you actually ask for them. So lazy loading works fine.


I think you've misunderstood, the section of the manual you've quoted is entitled "Performance impact", they're not telling you you can't do this, only that there are performance implications if you do. This makes sense for lazy loading - for heterogeneous collections of STI entities you have to go to the database and load the entity before you know what class it will be, so lazy loading isn't possible / doesn't make sense. I'm learning Doctrine 2 myself at the moment, so I mocked up your example, the following works OK for more:

namespace Entities;

/**
 * @Entity
 * @Table(name="pets")
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="pet_type", type="string")
 * @DiscriminatorMap({"cat" = "Cat", "dog" = "Dog"})
 */
class Pet
{
    /** @Id @Column(type="integer") @generatedValue */
    private $id;

    /** @Column(type="string", length=300) */
    private $name;

    /** @ManyToOne(targetEntity="User", inversedBy="id") */
    private $owner;
}


/** @Entity */
class Dog extends Pet
{

    /** @Column(type="string", length=50) */
    private $kennels;
}

/** @Entity */
class Cat extends Pet
{
    /** @Column(type="string", length=50) */
    private $cattery;
}

/**
 * @Entity
 * @Table(name="users")
 */
class User
{

    /** @Id @Column(type="integer") @generatedValue */
    private $id;

    /** @Column(length=255, nullable=false) */
    private $name;


    /** @OneToMany(targetEntity="Pet", mappedBy="owner") */
    private $pets;
}

... and the test script ....

if (false) {
    $u = new Entities\User;
    $u->setName("Robin");

    $p = new Entities\Cat($u, 'Socks');
    $p2 = new Entities\Dog($u, 'Rover');

    $em->persist($u);
    $em->persist($p);
    $em->persist($p2);
    $em->flush();
} else if (true) {
    $u = $em->find('Entities\User', 1);
    foreach ($u->getPets() as $p) {
        printf("User %s has a pet type %s called %s\n", $u->getName(), get_class($p), $p->getName());
    }
} else {
    echo "  [1]\n";
    $p = $em->find('Entities\Cat', 2);
    echo "  [2]\n";
    printf("Pet %s has an owner called %s\n", $p->getName(), $p->getOwner()->getName());
}

All my cats and dogs load as the correct type:

If you look at the generated SQL, you'll notice that when the OneToMany targetEntity is "pet", you get SQL like this:

SELECT t0.id AS id1, t0.name AS name2, t0.owner_id AS owner_id3, pet_type, 
t0.cattery AS cattery4, t0.kennels AS kennels5 FROM pets t0 
WHERE t0.owner_id = ? AND t0.pet_type IN ('cat', 'dog')

But when it's set to Cat, you get this:

SELECT t0.id AS id1, t0.name AS name2, t0.cattery AS cattery3, t0.owner_id 
AS owner_id4, pet_type FROM pets t0 WHERE t0.owner_id = ? AND t0.pet_type IN ('cat')

HTH.

ReferenceURL : https://stackoverflow.com/questions/5715777/doctrine-2-inheritance-mapping-with-association

반응형