繁体   English   中英

Doctrine2多对一关联不会使用JOIN查询

[英]Doctrine2 many-to-one association won't use JOIN query

我有一个与实体Owner多对一关系的Car实体。 如果我选择所有汽车,Doctrine会在Car表上执行一次查询,然后在Owner表上对每辆汽车进行一次查询。 因此,获取N个汽车变为N + 1个查询,而不是CarOwner表之间的单个JOIN查询。

我的实体如下:

/** @Entity */
class Car {

  /** @Id @Column(type="smallint") */
  private $id;

  /** @ManyToOne(targetEntity="Owner", fetch="EAGER")
      @JoinColumn(name="owner", referencedColumnName="id") */
  private $owner;

  public function getId()    { return $this->id; }
  public function getOwner() { return $this->owner; }
}

/** @Entity */
class Owner {

  /** @Id @Column(type="smallint") */
  private $id;

  /** @Column(type="string") */
  private $name;

  public function getName() { return $this->name; }
}

如果我想与他们的车主列出汽车,我会这样做:

$repo = $em->getRepository('Car');
$cars = $repo->findAll();

foreach($cars as $car) 
  echo 'Car no. ' . $car->getId() . 
       ' owned by ' . $car->getOwner()->getName() . '\n';

现在这一切都很有效,除了Doctrine为每辆车发出查询这一事实。

SELECT * FROM Car;
SELECT * FROM Owner WHERE id = 1;
SELECT * FROM Owner WHERE id = 2;
SELECT * FROM Owner WHERE id = 3;
....

当然我希望我的查询日志看起来像这样:

SELECT * FROM Car JOIN Owner ON Car.owner = Owner.id;

我是否有fetch="EAGER"fetch="LAZY"并不重要,即使我在两个实体之间使用JOIN进行自定义DQL查询, $car->getOwner()仍会导致Doctrine查询数据库(除非我使用EAGER,在这种情况下$repo->findAll()导致所有这些)。

我在这里太累了,这是它应该工作的方式 - 或者是否有一种聪明的方法来迫使Doctrine进行JOIN查询?

至少在1.x Doctrine中如果要查询相关对象,则必须使用DQL。 对于您的情况,DQL查询看起来像这样:

//Assuming $em is EntityManager
$query = $em->createQuery('SELECT c, o FROM Car c JOIN c.owner o');
$cars = $query->execute();

先运行DQL查询,然后选择与所有者联接的所有汽车(DQL JOIN)。 将所有者放在select()

// preload cars
$qb = $em->createQueryBuilder()
        ->select('car, owner')
        ->from('\Entity\Car', 'car')
        ->leftJoin('c.owner',  'owner');

    $query = $qb->getQuery();

    // the following seems not needed, but I think it depends on the conf
    $query->setFetchMode("\Entity\Car", "owner", "EAGER");

    $query->execute(); //you don't have to use this result here, Doctrine will keep it

然后,Doctrine 2将执行JOIN(通常更快,因为它需要更少的db查询,具体取决于记录的数量)。 现在启动你的foreach ,Doctrine将在内部找到实体,当你需要owner时它不会运行单个查询。

监控每次更改后的查询次数(例如,mysql常规日志)

您的查询...

$car->getOwner() // "go and fetch this car's owner"

...在foreach循环中,因此它肯定会多次发出查询。

如果你正在编写自定义DQL来处理这个问题,那么$car->getOwner()就不应该具有这个功能了。 这是Car类的功能。 您要编写的自定义DQL将模仿您指出的确切SQL查询并有效地完成连接。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM