简体   繁体   English

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

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

I have a Car entity with a many-to-one relationship with an entity Owner . 我有一个与实体Owner多对一关系的Car实体。 If I select all cars, Doctrine does one query on the Car table, and subsequently one query on the Owner table for each car . 如果我选择所有汽车,Doctrine会在Car表上执行一次查询,然后在Owner表上对每辆汽车进行一次查询。 So fetching N cars becomes N+1 queries instead of a single JOIN query between the Car and Owner tables. 因此,获取N个汽车变为N + 1个查询,而不是CarOwner表之间的单个JOIN查询。

My entities are as follows: 我的实体如下:

/** @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; }
}

If I want to list the cars with their owners, I do: 如果我想与他们的车主列出汽车,我会这样做:

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

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

Now this all works very well, apart from the fact that Doctrine issues a query for each car. 现在这一切都很有效,除了Doctrine为每辆车发出查询这一事实。

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

Of course I'd want my query log to look like this: 当然我希望我的查询日志看起来像这样:

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

Whether I have fetch="EAGER" or fetch="LAZY" doesn't matter, and even if I make a custom DQL query with JOIN between the two entities, $car->getOwner() still causes Doctrine to query the database (unless I use EAGER, in which case $repo->findAll() causes all of them). 我是否有fetch="EAGER"fetch="LAZY"并不重要,即使我在两个实体之间使用JOIN进行自定义DQL查询, $car->getOwner()仍会导致Doctrine查询数据库(除非我使用EAGER,在这种情况下$repo->findAll()导致所有这些)。

Am I just too tired here, and this is the way it is supposed to work - or is there a clever way to force Doctrine to do the JOIN query instead? 我在这里太累了,这是它应该工作的方式 - 或者是否有一种聪明的方法来迫使Doctrine进行JOIN查询?

At least in 1.x Doctrine if you wanted to query for the related objects, you had to use DQL. 至少在1.x Doctrine中如果要查询相关对象,则必须使用DQL。 For your case, the DQL query would look something like this: 对于您的情况,DQL查询看起来像这样:

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

Run first a DQL query where you select all the cars joined (DQL JOIN) with the owner. 先运行DQL查询,然后选择与所有者联接的所有汽车(DQL JOIN)。 Put the owner in the select() . 将所有者放在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 will then perform a JOIN (normally faster as it requires less db queries depending on the number of records). 然后,Doctrine 2将执行JOIN(通常更快,因为它需要更少的db查询,具体取决于记录的数量)。 Now launch your foreach , Doctrine will find the entities internally and it won't run single queries when you need the owner . 现在启动你的foreach ,Doctrine将在内部找到实体,当你需要owner时它不会运行单个查询。

Monitor the number of queries first/after each change (eg. mysql general log) 监控每次更改后的查询次数(例如,mysql常规日志)

Your query... 您的查询...

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

... is in a foreach loop so it will certainly issue the query several times. ...在foreach循环中,因此它肯定会多次发出查询。

If you're writing custom DQL to deal with this, $car->getOwner() shouldn't feature in this at all. 如果你正在编写自定义DQL来处理这个问题,那么$car->getOwner()就不应该具有这个功能了。 This is a function of the Car class. 这是Car类的功能。 The custom DQL you would write would mimick the exact SQL query you point out and get your join done efficiently. 您要编写的自定义DQL将模仿您指出的确切SQL查询并有效地完成连接。

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

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