day19(を6日過ぎた)今日はn+1問題を避けるためにまとめてデータを取得する方法を見ていきます。
Doctrine
Entity/Author.php
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'authors')]
class Author
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private int $id;
#[ORM\Column(type: 'string', length: 255)]
private string $name;
#[ORM\OneToMany(mappedBy: 'author', targetEntity: Book::class, fetch: 'EAGER')]
private Collection $books;
public function __construct()
{
$this->books = new ArrayCollection();
}
public function getId(): int
{
return $this->id;
}
public function setId(int $id): void
{
$this->id = $id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getBooks(): Collection
{
return $this->books;
}
public function addBook(Book $book): void
{
if (!$this->books->contains($book)) {
$book->setAuthor($this);
$this->books->add($book);
}
}
}
<?php
declare(strict_types=1);
use App\Entity\Author;
use Doctrine\ORM\EntityManagerInterface;
require __DIR__.'/../vendor/autoload.php';
/** @var EntityManagerInterface $entityManager */
$entityManager = require __DIR__.'/bootstrap.php';
/** @var Author[] $authors */
$authors = $entityManager->getRepository(Author::class)->findAll();
foreach ($authors as $author) {
echo $author->getName().PHP_EOL;
foreach ($author->getBooks() as $book) {
echo $book->getTitle().PHP_EOL;
}
}
// 実行されたSQLのログ
// doctrine.DEBUG: Executing query: {sql} {"sql":"SELECT t0.id AS id_1, t0.name AS name_2, t3.id AS id_4, t3.title AS title_5, t3.price AS price_6, t3.description AS description_7, t3.author_id AS author_id_8 FROM authors t0 LEFT JOIN books t3 ON t3.author_id = t0.id"} []
-
Author::$books
にfetch: 'EAGER'
を設定すると、SQL的にはjoinした状態で取得したものをAuthorエンティティとBookエンティティとして構築してくれます。
Eloquent
<?php
declare(strict_types=1);
use App\Models\Author;
require __DIR__.'/../vendor/autoload.php';
require __DIR__.'/bootstrap.php';
$authors = Author::with('books')->get();
foreach ($authors as $author) {
echo $author->name.PHP_EOL;
foreach ($author->books as $book) {
echo $book->title.PHP_EOL;
}
}
- modelに指定するのではなく取得時に指定します。