Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
426 views
in Technique[技术] by (71.8m points)

php - Doctrine 2 Inheritance Mapping with Association

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 there are 2 ways :

  • Single table inheritance (STI)
  • Class table inheritance (CTI)

For both, there is the warning :

If you use a STI/CTI entity as a many-to-one or one-to-one entity you should never use one of the classes at the upper levels of the inheritance hierachy as “targetEntity”, only those that have no subclasses. Otherwise Doctrine CANNOT create proxy instances of this entity and will ALWAYS load the entity eagerly.

So, how can I proceed to use inheritance with an association to the base (abstract) class ? (and keep the performance of course)


Example

A user has many Pet (abstract class extended by Dog or Cat).

What I want to do :

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

Because of the warning in Doctrine documentation, I should do that :

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

This is annoying, because I loose the benefits of inheritance !

Note : I didn't add the Doctrine annotations for the mapping to DB, but you can understand what I mean

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'm tired, but this seems like much ado about nothing.

You missed the important bit of that warning:

If you use a STI/CTI entity as a many-to-one or one-to-one entity

That's not the case in your example! If you had not omitted the doctrine annotations, you might have noticed.

The association User::pets is OneToMany, not [One|Many]ToOne. One user has many pets.

The inverse association is OneToOne, but it's targeting User, which has no inheritance.

Robin's answer should have been a good hint -- you can log the sql queries and see what doctrine actually does to your database!


The bad-for-performance scenario is something like:

abstract class Pet { ... }

class Cat extends Pet { ... } 

class Dog extends Pet { ... }

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

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

Now, if you wanted to iterate over all the blue collars, Doctrine runs into some trouble. It doesn't know what class $owner is going to be, so it can't use a Proxy. Instead, it's forced to eagerly load $owner to find out whether it's a Cat or a Dog.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...