Doctrine 2 - Eager loading似乎不适用于ManyToMany

时间:2017-08-05 02:54:46

标签: php symfony doctrine-orm eager-loading

我有三个实体:SequenceRun有一个MaterialTypeString,并且有很多User。即SequenceRunMaterialTypeString之间存在OneToMany关系,SequenceRunUser之间存在ManyToMany关系。

SequenceRun.php:

/**
 * @ORM\ManyToOne(targetEntity="MaterialTypeStrings", inversedBy="sequenceRuns")
 * @ORM\JoinColumn(name="material_type_strings_id", referencedColumnName="id")
 */
private $materialTypeString;

 /**
  * Many Groups have Many Users.
  * @ORM\ManyToMany(targetEntity="FOSUser", mappedBy="sequenceRuns")
  */
 private $users;

现在没有急于加载我的索引方法:

/**
 * @Route("/sequence_run/index", name="sequence_run_index")
 */
public function indexAction() {
    // Grab all experiments from database and hand them to template.
    $repository = $this->getDoctrine()->getRepository('AppBundle:SequenceRun');
    $sequence_runs = $repository->findAll();
    return $this->render('sequence_run/index.html.twig',['sequence_runs' => $sequence_runs]);
}

为单个SequenceRun对象生成4个查询:

SELECT t0.username AS username_1, t0.username_canonical AS username_canonical_2, t0.email AS email_3, t0.email_canonical AS email_canonical_4, t0.enabled AS enabled_5, t0.salt AS salt_6, t0.last_login AS last_login_7, t0.confirmation_token AS confirmation_token_8, t0.password_requested_at AS password_requested_at_9, t0.roles AS roles_10, t0.id AS id_11, t0.dn AS dn_12, t0.cn AS cn_13, t0.department AS department_14, t0.department_dn AS department_dn_15, t0.from_bio_control AS from_bio_control_16, t0.password AS password_17 FROM fos_user t0 WHERE t0.id = ? LIMIT 1
Parameters: [0 => 96]

SELECT t0.id AS id_1, t0.start_date AS start_date_2, t0.end_dat AS end_dat_3, t0.kit AS kit_4, t0.run_coverage_target AS run_coverage_target_5, t0.read_length AS read_length_6, t0.created_at AS created_at_7, t0.updated_at AS updated_at_8, t0.material_type_strings_id AS material_type_strings_id_9 FROM sequence_run t0
Parameters: []

SELECT t0.username AS username_1, t0.username_canonical AS username_canonical_2, t0.email AS email_3, t0.email_canonical AS email_canonical_4, t0.enabled AS enabled_5, t0.salt AS salt_6, t0.last_login AS last_login_7, t0.confirmation_token AS confirmation_token_8, t0.password_requested_at AS password_requested_at_9, t0.roles AS roles_10, t0.id AS id_11, t0.dn AS dn_12, t0.cn AS cn_13, t0.department AS department_14, t0.department_dn AS department_dn_15, t0.from_bio_control AS from_bio_control_16, t0.password AS password_17 FROM fos_user t0 INNER JOIN users_sequence_runs ON t0.id = users_sequence_runs.fosuser_id WHERE users_sequence_runs.sequence_run_id = ?
Parameters: [0 => 2]

SELECT t0.id AS id_1, t0.type AS type_2 FROM material_type_strings t0 WHERE t0.id = ?
Parameters: [0 => 5]

如果我将fetch = "EAGER"添加到MaterialTypeString,则会删除最后一个查询(按预期方式)。但是,如果我添加它还添加到User我仍然会得到3个查询。

eager加载是否适用于ManyToMany关系,还是我必须使用DQL并手动编写查询? (如果是这样的话会是什么样的?)

1 个答案:

答案 0 :(得分:1)

你想要达到什么目的?如果您希望针对dB获取所有需要的实体的单个查询,则需要手动编写自定义查询,这不是急切或延迟加载的问题。

你可以写这样的东西

$sequence_runs=$repository->createQueryBuilder('sr')->addSelect(['mts', 'fu'])
->leftJoin('sr.materialTypeString', 'mts')
->leftJoin('sr.users', 'fu')
->getQuery()->getResult();

如果您希望教义执行所有必需的查询,无论您是否在代码中使用关联,都使用急切加载,而使用延迟加载只有在代码中访问它们时才能使关联完全保持水分,但是如果您访问代码中的所有关联,查询的数量将是相同的。

重点是:您是否显示了实体的分页列表?然后,尝试使用DQL或查询构建器编写自己的查询,根据您的视图获取加载所有必需的实体。你在展示一个实体吗?然后从存储库中取出它,延迟加载你的关联,并让doctrine完成这项工作!