55 votos

Doctrina 2 asignación de herencia con la Asociación

NOTA : si lo que quiero no es posible, "no es posible" respuesta será aceptada

En la Doctrina 2 documentación sobre la asignación de la herencia, se dice que hay 2 maneras :

  • Tabla única herencia (ITS)
  • Tabla de clases de herencia (CTI)

Por tanto, existe la advertencia :

Si utiliza una ITS/CTI de la entidad como muchos-a-uno o uno-a-uno de la entidad nunca se debe utilizar una de las clases en los niveles superiores de la jerarquía de herencia como "targetEntity", sólo los que no tienen subclases. De lo contrario, la Doctrina NO puede crear proxy instancias de esta entidad y será SIEMPRE la carga de la entidad con impaciencia.

Así que, ¿cómo puedo proceder a utilizar la herencia con una asociación a la base (abstracta) de la clase ? (y mantener el rendimiento de curso)


Ejemplo

Un usuario tiene muchas Pet (clase abstracta ampliada por Dog o Cat).

Lo que quiero hacer :

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

Debido a la advertencia en la Doctrina de la documentación, que debo hacer :

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

Esto es molesto, porque voy a perder los beneficios de la herencia !

Nota : yo no agregar la Doctrina anotaciones para la asignación de DB, pero se puede entender lo que quiero decir

47voto

timdev Puntos 25910

Estoy cansado, pero esto parece mucho ado sobre nada.

Te perdiste la parte importante de esta advertencia:

Si utiliza una ITS/CTI de la entidad como muchos-a-uno o uno-a-uno de la entidad

Que no es el caso de tu ejemplo! Si no hubiera omitido la doctrina anotaciones, usted puede haber notado.

La asociación de Usuario::mascotas es OneToMany, no [Uno|Muchos]Tono. Un usuario tiene muchas mascotas.

La asociación inversa es OneToOne, pero es la orientación del Usuario, que no tiene herencia.

Robin respuesta debería haber sido una buena pista -- puede registrar las consultas sql y ver lo que la doctrina en realidad hace a su base de datos!


Lo malo-para-escenario de actuación es algo así como:

abstract class Pet { ... }

class Cat extends Pet { ... } 

class Dog extends Pet { ... }

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

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

Ahora, si usted quiere iterar sobre todos los cuellos azules, la Doctrina se ejecuta en algunos problemas. No se sabe en qué clase de dólares propietario va a ser, por lo que no se puede utilizar un Proxy. En su lugar, es obligado para con impaciencia carga $propietario para averiguar si es un Gato o un Perro.

Este no es un problema para OneToMany o ManyToMany relaciones, porque en ese caso, la carga diferida funciona bien. En lugar de un proxy, se obtiene un PersistentCollection. Y un PersistentCollection es siempre sólo un PersistentCollection. No le importa acerca de su propio contenido hasta que pida por ellos. Tan perezoso de carga funciona bien.

46voto

Robin Puntos 2615

Creo que lo he entendido mal, en la sección del manual que has citado es titulado "impacto en el Rendimiento", no estamos diciendo que usted no puede hacer esto, sólo que hay consecuencias en el rendimiento. Esto tiene sentido para la carga diferida - para colecciones heterogéneas de ITS entidades que tienen que ir a la base de datos y carga de la entidad antes de saber qué clase va a ser, por lo que la carga diferida no es posible / no tiene sentido. Estoy aprendiendo la Doctrina de 2 a mí mismo en el momento, así que se burlaban de su ejemplo, las siguientes obras: OK para más:

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;
}

... y la secuencia de comandos de prueba....

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());
}

Todos mis gatos y perros de la carga como el tipo correcto:

Si usted mira el SQL generado, te darás cuenta de que cuando el OneToMany targetEntity es la "mascota", consigue SQL como este:

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')

Pero cuando se trata de un set de Gato, usted consigue esto:

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.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X