php 如何在 Doctrine2 中使用 EntityManager 检索具有所有关联的实体?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8420175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 04:39:52  来源:igfitidea点击:

How to retrieve an entity with all of its associations using EntityManager in Doctrine2?

phpdoctrine-ormdoctrine

提问by Mehdi Fanai

I have a simple entity with many-to-many and one-to-many associations. I'm aware of 'Joins' for fetching related associations which is a manual solution for my problem.

我有一个具有多对多和一对多关联的简单实体。我知道用于获取相关关联的“连接”,这是针对我的问题的手动解决方案。

How can I fetch an entity with all of its associations using EntityManager in Doctrine2? e.g.:

如何使用 Doctrine2 中的 EntityManager 获取具有所有关联的实体?例如:

$this->em
     ->getRepository('Entities\Patientprofile')
     ->findOneByuserid('555555557')
     ->fetchAllAssociations();

回答by timaschew

from http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#temporarily-change-fetch-mode-in-dql

来自http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#temporously-change-fetch-mode-in-dql

you can set eagerfetch mode temporarily:

您可以暂时设置急切获取模式:

$query = $em->createQuery("SELECT u FROM MyProject\User u");
$query->setFetchMode("MyProject\User", "address", "EAGER");
$query->execute();

If you want do load dynamically all associations with this fetch mode, you can use the getAssociationMappings()method of the Doctrine\ORM\Mapping\ClassMetadataInfo, passing your entity name as parameter to the constructor of ClassMetadataInfoand then iterate over the returned array as $assocand call:

如果你想动态加载所有与此获取模式的关联,你可以使用 的getAssociationMappings()方法Doctrine\ORM\Mapping\ClassMetadataInfo,将你的实体名称作为参数传递给 的构造函数,ClassMetadataInfo然后迭代返回的数组作为$assoc并调用:

$query->setFetchMode("MyProject\User", $assoc, "EAGER");

Doc: ClassMetadataInfo#getAssociationMappings()

文档:ClassMetadataInfo#getAssociationMappings()

回答by Wilt

Doctrine2 setFetchMode not working with "EAGER"

Doctrine2 setFetchMode 不适用于“EAGER”

I tried also to fetch the associating entities "eagerly" using setFetchModein my query, but the following didn't seem to work:

我还尝试setFetchMode在我的查询中“热切地”使用关联实体,但以下内容似乎不起作用:

$query->setFetchMode("MyProject\User", "address", "EAGER");

When I jumped into the files I found out that the third parameter $fetchModeshould be an integer. The constants are defined in Doctrine\ORM\Mapping:ClassMetadataInfo. When passing a string it will default to Mapping\ClassMetadata::FETCH_LAZYbecause of this if clause.

当我跳入文件时,我发现第三个参数$fetchMode应该是一个 integer。常量在 Doctrine\ORM\Mapping:ClassMetadataInfo 中定义。当传递一个字符串时,它会Mapping\ClassMetadata::FETCH_LAZY因为这个 if 子句而默认为。

/**
 * Specifies that an association is to be fetched when it is first accessed.
 */
const FETCH_LAZY = 2;

/**
 * Specifies that an association is to be fetched when the owner of the
 * association is fetched.
 */
const FETCH_EAGER = 3;

/**
 * Specifies that an association is to be fetched lazy (on first access) and that
 * commands such as Collection#count, Collection#slice are issued directly against
 * the database if the collection is not yet initialized.
 */
const FETCH_EXTRA_LAZY = 4;

So setting the corresponding integer solved the problem:

于是设置相应的整数就解决了问题:

$query->setFetchMode("MyProject\User", "address", 3);

Or declare the class use Doctrine\ORM\Mapping\ClassMetadataat the top and then use the constant:

或者use Doctrine\ORM\Mapping\ClassMetadata在顶部声明类,然后使用常量:

$query->setFetchMode("MyProject\User", "address", ClassMetadata::FETCH_EAGER);


EDIT:

编辑:

Since there seems to be a lot of confusion here on how to fetch associations the right way I will edit my answer and add some additional information on how you can fetch join using your repository.

由于这里似乎对如何以正确的方式获取关联存在很多混淆,因此我将编辑我的答案并添加一些有关如何使用存储库获取连接的附加信息。

According to the Doctrine documentationthere are 2 types of joins:

根据 Doctrine 文档,有两种类型的连接:

  1. Regular Joins: Used to limit the results and/or compute aggregate values.

  2. Fetch Joins: In addition to the uses of regular joins: Used to fetch related entities and include them in the hydrated result of a query.

  1. 常规连接:用于限制结果和/或计算聚合值。

  2. 获取连接:除了常规连接的使用之外:用于获取相关实体并将它们包含在查询的水合结果中。

So to get an entity including its associations you will need to "fetch-join" all these associations to make sure they are loaded eagerly.

因此,要获取包含其关联的实体,您需要“获取-加入”所有这些关联以确保它们被急切地加载。

I usually don't use DQL queries for getting entities and solving my fetch joins, instead I add a custom method to a repository where I use a query builder. This is more flexible and much more readable then using DQL. The correct DQL query will be created by the query builder when we call the createQuerymethod. You can check the created DQL query of course for debug purposes.

我通常不使用 DQL 查询来获取实体和解决我的获取连接,而是将自定义方法添加到使用查询构建器的存储库中。与使用 DQL 相比,这更灵活且更具可读性。当我们调用该createQuery方法时,查询构建器将创建正确的 DQL 查询。您当然可以检查创建的 DQL 查询以进行调试。

An example for such a custom method inside the Patientprofileentity repository from the question above:

Patientprofile来自上述问题的实体存储库中此类自定义方法的示例:

public function findPatientByIdWithAssociations($id)(
    // create a query builder for patient with alias 'p'
    $qb = $this->createQueryBuilder('p')
               ->where('p.id = :patient_id')
               ->addSelect('pd')
               ->leftJoin('p.documentation', 'pd')
               ->addSelect('pa')
               ->leftJoin('p.address', 'pa')
               ->setParameter('patient_id', $id);

    $query = $queryBuilder->getQuery();
    return $query->getSingleResult();
}

And now you can use your custom repository method to get the patient by id (for example '555555557') including associations to the patient documentation and address:

现在,您可以使用自定义存储库方法通过 id(例如“555555557”)获取患者,包括与患者文档和地址的关联:

$repository = $this->em->getRepository('Entities\Patientprofile');
$patient = $repository->findPatientByIdWithAssociations('555555557');

Make sure you use both addSelectand leftJointo do eager loading.

确保同时使用addSelectleftJoin进行急切加载。

回答by chriswoodford

Doctrine 2 uses Proxy classes for lazy loading, so you don't actually need to have the associations' data fetched until you use the objects. Since the Proxy classes inherit from your association classes, you're able to use the proxies exactly as you would use the fretch association classes.

Doctrine 2 使用代理类进行延迟加载,因此您实际上不需要在使用对象之前获取关联的数据。由于 Proxy 类继承自您的关联类,因此您可以像使用 freetch 关联类一样使用代理。

but, if you really need to fetch the actual association classes, you need to tell the query to set the fetch mode to Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER. If you're using the annotations, you can achieve this with:

但是,如果你真的需要获取实际的关联类,你需要告诉查询将获取模式设置为 Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER。如果您正在使用注释,则可以通过以下方式实现:

e.g.

例如

/**
 * @ManyToMany(targetEntity="Item", fetch="EAGER")
 */
private $items;

回答by Maxence

You can use a DQL query:

您可以使用 DQL 查询:

$query = $em->createQuery("SELECT p, f FROM Entities\Patientprofile p JOIN p.Foo f WHERE p.id = ?1");
$query->setParameter(1, 321);
$patient = $query->getSingleResult();