Doctrineで1対1のjoinをした場合、不必要なSQLが発行される場合があります。
要は、Lazy Loadが起こってしまうということです。
1対多で起こるLazy Loadについては、以下の記事で書いています。
PHPのDoctrineでSQLが乱発される事象について
以下は、userとaddressが1対1のリレーションを持っているEntityです。
※この記事ではDoctrine 2.4.7を使用しています。
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;
}
}
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;
}
}
ここで、ユーザーを全て取得するために
$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が必要です。
$this->createQueryBuilder('user')->getQuery()->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)->getResult();
こうすることによって、余計なSQLが発行されずに全ユーザーのデータを取得することができます。
Entityに複数のOneToOneのJOINが定義されている場合は必要に応じて
setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
を忘れないようにしましよう!
投稿者プロフィール
最新の投稿
AWS2021年12月2日AWS Graviton3 プロセッサを搭載した EC2 C7g インスタンスが発表されました。
セキュリティ2021年7月14日ゼロデイ攻撃とは
セキュリティ2021年7月14日マルウェアとは
WAF2021年7月13日クロスサイトスクリプティングとは?



