Tengo una entidad Car
con una relación de varios a uno con una entidad Owner
. Si selecciono todos los automóviles, Doctrine realiza una consulta en la tabla Car
y, posteriormente, una consulta en la tabla Owner
para cada auto. 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
.La asociación muchos-a-uno de Doctrine2 no usará la consulta JOIN
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 una lista de los coches con sus dueños, que hago:
$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 automóvil.
SELECT * FROM Car;
SELECT * FROM Owner WHERE id = 1;
SELECT * FROM Owner WHERE id = 2;
SELECT * FROM Owner WHERE id = 3;
....
Por supuesto que me gustaría que mi registro de consultas a tener este aspecto:
SELECT * FROM Car JOIN Owner ON Car.owner = Owner.id;
si tengo fetch="EAGER"
o fetch="LAZY"
no importa, e incluso si hago una consulta DQL personalizado 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()
los causa a todos).
¿Estoy demasiado cansado aquí, y esta es la forma en que se supone que funciona, o hay una manera inteligente de forzar a Doctrine a hacer la consulta JOIN en su lugar?
Parece que es también el caso en 2.x. Había intentado la consulta 'SELECT c FROM Car c JOIN c.owner o', que todavía hacía consultas N + 1, pero la tuya funcionaba muy bien. ¡Muchas gracias! Supongo que tendré que vivir sin usar los métodos findXxx. – Frode
Para métodos de conveniencia como ese, sugiero crear una clase de estilo "capa de servicio" o "repositorio" que maneje tareas como cargar modelos. De esta forma, también podría reutilizar fácilmente la consulta sin tener que duplicar la lógica DQL por todos lados. –