Login to bookmark this video
Buy Access to Course
09.

Ordenar una Relación y tipo "buscar

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Haz clic en una nave "en curso". A continuación, abre: templates/starship/show.html.twig. Para ordenar las piezas, utiliza for part in ship.parts.

Esto funcionará a las mil maravillas. Pero con una pega: el orden de las piezas no está garantizado. ¡Salen de la base de datos en el orden que quieran!

Preferiría tenerlas ordenadas por nombre. ¿Significa esto que tenemos que escribir una consulta personalizada... y que ya no podemos utilizar nuestro práctico ship.parts?

¡No temáis, amigos! ¡Aprendamos algunos trucos!

Reorganizar las partes

Dirígete a la entidad Starship y busca la propiedad parts. Encima de parts, añade un nuevo atributo: #[ORM\OrderBy(['name' => 'ASC'])], no position:

183 lines | src/Entity/Starship.php
// ... lines 1 - 13
class Starship
{
// ... lines 16 - 45
#[ORM\OrderBy(['name' => 'ASC'])]
private Collection $parts;
// ... lines 48 - 181
}

Actualiza la página, ¡y ya está!

Si te estás rascando la cabeza preguntándote por qué T va antes que c, no has olvidado el abecedario. Es que Postgres es una base de datos que distingue entre mayúsculas y minúsculas. Así que la T mayúscula aparentemente va antes que la C minúscula en orden alfabético.

Consultas inteligentes

Comprueba las consultas de esta página y visualiza el SQL formateado. Consulta desde starship_part, donde starship_id es igual a nuestro ID, ordenado por name de forma ascendente: ¡es exactamente la consulta que queremos!

El problema N+1

Vuelve a la página de inicio y abre su plantilla:templates/main/homepage.html.twig. Después de "llegado", añade un div e imprime el recuento de piezas: ship.parts|length:

75 lines | templates/main/homepage.html.twig
// ... lines 1 - 4
{% block body %}
<main class="flex flex-col lg:flex-row">
// ... lines 7 - 8
<div class="px-12 pt-10 w-full">
// ... lines 10 - 17
<div class="space-y-5">
{% for ship in ships %}
<div class="bg-[#16202A] rounded-2xl pl-5 py-5 pr-11 flex flex-col min-[1174px]:flex-row min-[1174px]:justify-between">
<div class="flex justify-center min-[1174px]:justify-start">
// ... line 22
<div class="ml-5">
// ... lines 24 - 33
<div>
Arrived: {{ ship.arrivedAt|ago }}
</div>
<div>
Parts: {{ ship.parts|length }}
</div>
</div>
</div>
// ... lines 42 - 52
</div>
{% endfor %}
</div>
// ... lines 56 - 71
</div>
</main>
{% endblock %}

De vuelta a la página principal, funciona a las mil maravillas. Echa un vistazo a las consultas de esta página, son interesantes. Algunas parecen un poco locas debido a nuestra paginación, pero esencialmente, tenemos una consulta para la nave estelar, y si buscamos starship_part, hay 5 consultas adicionales para las piezas de cada nave estelar.

Esto es lo que ocurre: cogemos las naves estelares, y en cuanto contamos ship.parts, Doctrine se da cuenta de que aún no tiene esos datos. Así que busca una a una todas las piezas de cada nave y las cuenta. Ésta es una situación habitual: tenemos una consulta para las naves y luego una consulta adicional para las piezas de cada nave. Se conoce como el problema N+1: 1 consulta para las naves y N consultas para las piezas de cada nave. Es un problema menor de rendimiento que abordaremos más adelante.

Consultas eficientes

¡Pero aquí hay un problema mayor! Consultamos cadastarship_part sólo para contarlas. No necesitamos los datos de las piezas, sólo necesitamos saber cuántas tenemos. Esto es menor... hasta que tienes una nave con una tonelada de piezas.

Para solucionarlo, en el OneToMany en la entidad Starship, añade una opción fetch establecida en EXTRA_LAZY:

183 lines | src/Entity/Starship.php
// ... lines 1 - 13
class Starship
{
// ... lines 16 - 44
#[ORM\OneToMany(targetEntity: StarshipPart::class, mappedBy: 'starship', fetch: 'EXTRA_LAZY', orphanRemoval: true)]
// ... line 46
private Collection $parts;
// ... lines 48 - 181
}

¡Vamos a ver qué ha hecho!

Contando las Piezas

Vuelve a la página principal. Antes teníamos nueve consultas... ¿Ahora? Siguen siendo nueve consultas, pero la consulta de las piezas ha cambiado. En lugar de consultar todos sus datos, sólo los cuenta. Mucho más inteligente, ¿verdad?

Te estarás preguntando -yo ciertamente lo hice- por qué no utilizamos fetch="EXTRA_LAZY"todo el tiempo En primer lugar, se trata de una pequeña optimización del rendimiento de la que no tienes que preocuparte, a menos que tengas una nave llena de piezas y sólo quieras contarlas. Y lo que es más importante, dependiendo de si cuentas o haces un bucle sobre las piezas primero, esto podría causar una consulta extra.

El sistema de criterios

¡Pasemos al siguiente reto! ¿Qué pasa si sólo queremos las piezas relacionadas de una nave que cuestan más de un precio determinado? ¿Podemos seguir utilizando el acceso directo ship.partso tenemos que hacer una consulta personalizada? Permanece atento, vamos a explorar el sistema de criterios a continuación.