Lazy LoadによってSQLが乱発されデータベースの負荷が高くなる恐れがあるので注意しましょう。
Lazy Loadとは、必要なときにSQLを発行する仕組みです。
これから、例を示しながら説明していきます。
※この記事ではDoctrine 2.4.7を使用しています。
以下は、userとpostが1対多のリレーションを持っているEntityです。
class User implements UserInterface
{
public function __construct()
{
$this->posts = new ArrayCollection();
}
/**
* @var integer $id
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $name
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="Post", mappedBy="user")
* @var Post[] $posts
*/
private $posts;
/**
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return Post[]
*/
public function getPosts()
{
return $this->posts;
}
/**
* @param Post $post
*/
public function addPost($post)
{
$post->setUser($this);
$this->posts->add($post);
}
}
class Post
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=100, nullable=true, unique=false)
*/
private $title;
/**
* @var string
*
* @ORM\Column(name="body", type="text")
*/
private $body;
/**
* @var User
*
* @ORM\ManyToOne(targetEntity="User")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $user;
/**
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
*
* @param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
*
* @param string $body
*/
public function setBody($body)
{
$this->body = $body;
}
/**
*
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
*
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
*
* @param User $user
*/
public function setUser($user)
{
$this->user = $user;
}
}
そして、以下はユーザーとそれに紐づく投稿記事を取得するDQLです。
$qb = $this->createQueryBuilder('user');
$qb->select('user')
->leftJoin('user.posts', 'posts')
->where($qb->expr()->eq('user.id', $userId))
return $qb->getQuery()->getSingleResult();
上記の結果をuser変数に入れて、twigで使用すると
ユーザー名: {{ user.getName }}
投稿記事
{% for post in user.getPosts %}
タイトル: {{ post.getTitle }}
内容
{{ post.getBody }}
{% endfor %}
HTMLなどは省略しましたが、このようになります。
ポイントはfor文のuser.postsの部分です。
ここで新たにuserに紐づくpostを取得するためのSQLが発行されます。
よって、SQLが最低2回
$qb->getQuery()->getSingleResult()
の時と
user.getPosts
の時に発行されることになります。
postのデータが複数ある場合、その回数分SQLが発行されます。
なぜなら、DQLのselect句($qb->select('user'))でユーザーしかセレクトしていないため
そのオブジェクトのリレーションプロパティをgetするだけで「Doctrine が無言で二つ目のクエリを発行する」からです。
Lazy Loadを発生させないためには
$qb->select('user')
ではなく
$qb->select('user', 'posts')
としなけらばならないのです。
こうすることで、
$qb->getQuery()->getSingleResult()
の時の一回のSQLで、postの情報まで取得することができます。
投稿者プロフィール
最新の投稿
AWS2021年12月2日AWS Graviton3 プロセッサを搭載した EC2 C7g インスタンスが発表されました。
セキュリティ2021年7月14日ゼロデイ攻撃とは
セキュリティ2021年7月14日マルウェアとは
WAF2021年7月13日クロスサイトスクリプティングとは?
