Doctrineで1対1のjoinをした場合、不必要なSQLが発行される場合があります。
要は、Lazy Loadが起こってしまうということです。
1対多で起こるLazy Loadについては、以下の記事で書いています。
PHPのDoctrineでSQLが乱発される事象について
以下は、userとaddressが1対1のリレーションを持っているEntityです。
※この記事ではDoctrine 2.4.7を使用しています。
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 | class User implements UserInterface { /** * @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\OneToOne(targetEntity="Address", inversedBy="user") * @ORM\JoinColumn(name="address_id", referencedColumnName="id", nullable=true) * @var Address */ private $address ; /** * * @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 Address */ public function getAddress() { return $this ->address; } /** * @param Address $address */ public function setAddress( $address ) { $this ->address = $address ; } } |
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 | class Address { /** * @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 ; /** * @var User $user * @ORM\OneToOne(targetEntity="User", mappedBy="address") */ private $user ; /** * * @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 User */ public function getUser() { return $this ->user; } /** * @param User $user */ public function setUser( $user ) { $this ->user = $user ; } } |
ここで、ユーザーを全て取得するために
1 | $this ->get( 'doctrine.orm.entity_manager' )->getRepository( 'User' )->findAll(); |
とした場合、DoctrineはuserテーブルにaddressテーブルをLEFT JOINしたSQLを自動的に発行します。
以上のことから、Doctrineは、「Entityに定義されているOneToOneのJOINを自動的にLEFT JOINする」ということがわかります。
例えば、User Entityにaddressの他に2つOneToOneのJOINが定義されていたとしたら、
全ユーザーのデータが欲しいだけだったとしても、自動的に3つのテーブルがLEFT JOINされてしまいます。
これを防ぐためには、以下のDQLが必要です。
1 | $this ->createQueryBuilder( 'user' )->getQuery()->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)->getResult(); |
こうすることによって、余計なSQLが発行されずに全ユーザーのデータを取得することができます。
Entityに複数のOneToOneのJOINが定義されている場合は必要に応じて
1 | setHint(Query::HINT_FORCE_PARTIAL_LOAD, true) |
を忘れないようにしましよう!
投稿者プロフィール
最新の投稿
AWS2021年12月2日AWS Graviton3 プロセッサを搭載した EC2 C7g インスタンスが発表されました。
セキュリティ2021年7月14日ゼロデイ攻撃とは
セキュリティ2021年7月14日マルウェアとは
WAF2021年7月13日クロスサイトスクリプティングとは?