usar symfony2 getrepository getdoctrine consultas como php mysql doctrine2

php - symfony2 - La asociación muchos a uno de Doctrine2 no usará la consulta JOIN



findall symfony (3)

Tengo una entidad de Car con una relación de muchos a uno con el Owner una entidad. Si selecciono todos los automóviles, Doctrine hace una consulta en la tabla Car y, posteriormente, una consulta en la tabla Owner de cada automóvil . Así que ir a buscar N autos se convierte en N + 1 consultas en lugar de una sola consulta JOIN entre las tablas Car y Owner .

Mis entidades son las siguientes:

/** @Entity */ class Car { /** @Id @Column(type="smallint") */ private $id; /** @ManyToOne(targetEntity="Owner", fetch="EAGER") @JoinColumn(name="owner", referencedColumnName="id") */ private $owner; public function getId() { return $this->id; } public function getOwner() { return $this->owner; } } /** @Entity */ class Owner { /** @Id @Column(type="smallint") */ private $id; /** @Column(type="string") */ private $name; public function getName() { return $this->name; } }

Si quiero enumerar los autos con sus dueños, hago lo siguiente:

$repo = $em->getRepository(''Car''); $cars = $repo->findAll(); foreach($cars as $car) echo ''Car no. '' . $car->getId() . '' owned by '' . $car->getOwner()->getName() . ''/n'';

Ahora todo esto funciona muy bien, aparte del hecho de que Doctrine emite una consulta para cada auto.

SELECT * FROM Car; SELECT * FROM Owner WHERE id = 1; SELECT * FROM Owner WHERE id = 2; SELECT * FROM Owner WHERE id = 3; ....

Por supuesto, me gustaría que mi registro de consultas se viera así:

SELECT * FROM Car JOIN Owner ON Car.owner = Owner.id;

Si tengo fetch="EAGER" o fetch="LAZY" no importa, e incluso si realizo una consulta DQL personalizada con JOIN entre las dos entidades, $car->getOwner() todavía hace que Doctrine consulte la base de datos ( a menos que use EAGER, en cuyo caso $repo->findAll() causa a todos).

¿Estoy demasiado cansado aquí, y esta es la forma en que se supone que funciona, o hay una forma inteligente de forzar a Doctrine a hacer la consulta JOIN en su lugar?


Al menos en 1.x Doctrine, si desea consultar los objetos relacionados, debe usar DQL. Para su caso, la consulta DQL sería algo como esto:

//Assuming $em is EntityManager $query = $em->createQuery(''SELECT c, o FROM Car c JOIN c.owner o''); $cars = $query->execute();


Ejecute primero una consulta DQL donde seleccione todos los automóviles unidos (DQL JOIN) con el propietario. Coloque al propietario en la select() .

// preload cars $qb = $em->createQueryBuilder() ->select(''car, owner'') ->from(''/Entity/Car'', ''car'') ->leftJoin(''c.owner'', ''owner''); $query = $qb->getQuery(); // the following seems not needed, but I think it depends on the conf $query->setFetchMode("/Entity/Car", "owner", "EAGER"); $query->execute(); //you don''t have to use this result here, Doctrine will keep it

Doctrine 2 realizará un JOIN (normalmente más rápido ya que requiere menos consultas db según el número de registros). Ahora ejecute su foreach , Doctrine encontrará las entidades internamente y no ejecutará consultas individuales cuando necesite al owner .

Supervisa el número de consultas primero / después de cada cambio (p. Ej., Registro general de mysql)


Su consulta...

$car->getOwner() // "go and fetch this car''s owner"

... está en un bucle foreach, por lo que seguramente emitirá la consulta varias veces.

Si está escribiendo un DQL personalizado para manejar esto, $car->getOwner() no debería figurar en esto. Esta es una función de la clase Car. El DQL personalizado que escribiría imitaría la consulta SQL exacta que señala y hará que su unión se realice de manera eficiente.