Параметр fetch атрибута ManyToOne
Параметр fetch атрибута ManyToOne задаёт стратегию загрузки связанной сущности в Doctrine. Он определяет, когда именно будет выполнен SQL-запрос за связанными данными: сразу при загрузке основной сущности или лениво, в момент первого обращения к связи. По умолчанию используется значение LAZY.
Параметр принимает одно из значений: LAZY, EAGER или EXTRA_LAZY. Стратегия LAZY откладывает запрос до момента обращения, EAGER загружает связь сразу вместе с основной сущностью, а EXTRA_LAZY загружает данные только при реальном обращении к элементам коллекции.
Синтаксис
#[ManyToOne(targetEntity: Entity::class, fetch: 'LAZY')]
Пример
Давайте создадим сущность Article со связью ManyToOne на сущность Category и стратегией загрузки LAZY по умолчанию:
<?php
namespace AppEntity;
use AppRepositoryCategoryRepository;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: CategoryRepository::class)]
class Category
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMColumn(length: 255)]
private ?string $title = null;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
}
?>
Теперь создадим сущность Article со связью на Category:
<?php
namespace AppEntity;
use AppRepositoryArticleRepository;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: ArticleRepository::class)]
class Article
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMColumn(length: 255)]
private ?string $title = null;
#[ORMManyToOne(targetEntity: Category::class, fetch: 'LAZY')]
#[ORMJoinColumn(nullable: false)]
private ?Category $category = null;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): static
{
$this->category = $category;
return $this;
}
}
?>
При стратегии LAZY запрос к таблице category выполнится только при вызове метода getCategory:
<?php
namespace AppController;
use AppEntityArticle;
use DoctrineORMEntityManagerInterface;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAttributeRoute;
class ArticleController extends AbstractController
{
#[Route('/article/{id}', name: 'article_show')]
public function show(int $id, EntityManagerInterface $em): Response
{
$article = $em->getRepository(Article::class)->find($id);
// SQL-запрос за категорией выполнится только здесь
$title = $article->getCategory()->getTitle();
return new Response($title);
}
}
?>
Результат выполнения кода для адреса /article/1:
"abcde"
Пример
Давайте изменим стратегию на EAGER, чтобы категория загружалась сразу вместе со статьёй:
<?php
namespace AppEntity;
use AppRepositoryArticleRepository;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: ArticleRepository::class)]
class Article
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMColumn(length: 255)]
private ?string $title = null;
#[ORMManyToOne(targetEntity: Category::class, fetch: 'EAGER')]
#[ORMJoinColumn(nullable: false)]
private ?Category $category = null;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): static
{
$this->category = $category;
return $this;
}
}
?>
Теперь при выборке статьи Doctrine сразу выполнит JOIN и подгрузит категорию одним запросом:
<?php
namespace AppController;
use AppEntityArticle;
use DoctrineORMEntityManagerInterface;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAttributeRoute;
class ArticleController extends AbstractController
{
#[Route('/article/{id}', name: 'article_show')]
public function show(int $id, EntityManagerInterface $em): Response
{
$article = $em->getRepository(Article::class)->find($id);
// Категория уже загружена, дополнительного запроса не будет
$title = $article->getCategory()->getTitle();
return new Response($title);
}
}
?>
Результат выполнения кода для адреса /article/1:
"abcde"
Смотрите также
-
атрибут
ManyToOne,
который задаёт связь многие-к-одному -
параметр
targetEntity,
который указывает целевую сущность связи -
параметр
inversedBy,
который задаёт обратную сторону связи -
параметр
cascade,
который задаёт каскадные операции