Lazy LoadによってSQLが乱発されデータベースの負荷が高くなる恐れがあるので注意しましょう。
Lazy Loadとは、必要なときにSQLを発行する仕組みです。
これから、例を示しながら説明していきます。
※この記事ではDoctrine 2.4.7を使用しています。
以下は、userとpostが1対多のリレーションを持っているEntityです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 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 ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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です。
1 2 3 4 5 6 | $qb = $this ->createQueryBuilder( 'user' ); $qb ->select( 'user' ) ->leftJoin( 'user.posts' , 'posts' ) ->where( $qb ->expr()->eq( 'user.id' , $userId )) return $qb ->getQuery()->getSingleResult(); |
上記の結果をuser変数に入れて、twigで使用すると
1 2 3 4 5 6 7 8 9 | ユーザー名: {{ user.getName }} 投稿記事 {% for post in user.getPosts %} タイトル: {{ post.getTitle }} 内容 {{ post.getBody }} {% endfor %} |
HTMLなどは省略しましたが、このようになります。
ポイントはfor文のuser.postsの部分です。
ここで新たにuserに紐づくpostを取得するためのSQLが発行されます。
よって、SQLが最低2回
1 | $qb ->getQuery()->getSingleResult() |
の時と
1 | user.getPosts |
の時に発行されることになります。
postのデータが複数ある場合、その回数分SQLが発行されます。
なぜなら、DQLのselect句($qb->select('user'))でユーザーしかセレクトしていないため
そのオブジェクトのリレーションプロパティをgetするだけで「Doctrine が無言で二つ目のクエリを発行する」からです。
Lazy Loadを発生させないためには
1 | $qb ->select( 'user' ) |
ではなく
1 | $qb ->select( 'user' , 'posts' ) |
としなけらばならないのです。
こうすることで、
1 | $qb ->getQuery()->getSingleResult() |
の時の一回のSQLで、postの情報まで取得することができます。
投稿者プロフィール
最新の投稿
AWS2021年12月2日AWS Graviton3 プロセッサを搭載した EC2 C7g インスタンスが発表されました。
セキュリティ2021年7月14日ゼロデイ攻撃とは
セキュリティ2021年7月14日マルウェアとは
WAF2021年7月13日クロスサイトスクリプティングとは?