Doctrine 2 Inheritance Mapping with Association

后端 未结 2 1535
面向向阳花
面向向阳花 2020-12-07 09:53

NOTE : if what I want is not possible, a \"not possible\" answer will be accepted

In the Doctrine 2 documentation about inheritance mapping, it says

2条回答
  •  南笙
    南笙 (楼主)
    2020-12-07 10:27

    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.

提交回复
热议问题