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

Meh*_*nai 6 php doctrine doctrine-orm

我有一个简单的实体,具有多对多和一对多的关联.我知道'Joins'用于获取相关关联,这是我的问题的手动解决方案.

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

$this->em
     ->getRepository('Entities\Patientprofile')
     ->findOneByuserid('555555557')
     ->fetchAllAssociations();
Run Code Online (Sandbox Code Playgroud)

tim*_*hew 20

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

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

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

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

$query->setFetchMode("MyProject\User", $assoc, "EAGER");
Run Code Online (Sandbox Code Playgroud)

Doc:ClassMetadataInfo#getAssociationMappings()

  • 这种方法的热切加载有多深?只是包含在对象 U 中的对象,那些类中的任何对象都恢复为延迟加载?或者这个查询是否会加载链接到任何链接到 U 的任何内容? (2认同)

Wil*_*ilt 13

Doctrine2 setFetchMode无法使用"EAGER"

我还尝试setFetchMode在我的查询中"急切地"获取关联实体,但以下似乎不起作用:

$query->setFetchMode("MyProject\User", "address", "EAGER");
Run Code Online (Sandbox Code Playgroud)

当我跳进文件时,我发现第三个参数$fetchMode应该是一个整数.常量在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;
Run Code Online (Sandbox Code Playgroud)

所以设置相应的整数解决了问题:

$query->setFetchMode("MyProject\User", "address", 3);
Run Code Online (Sandbox Code Playgroud)

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

$query->setFetchMode("MyProject\User", "address", ClassMetadata::FETCH_EAGER);
Run Code Online (Sandbox Code Playgroud)

编辑:

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

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

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

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

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

我通常不使用DQL查询来获取实体并解决我的提取连接,而是将自定义方法添加到我使用查询构建器的存储库中.这比使用DQL更灵活,更易读.调用createQuery方法时,查询构建器将创建正确的DQL查询.您可以检查创建的DQL查询以进行调试.

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();
}
Run Code Online (Sandbox Code Playgroud)

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

$repository = $this->em->getRepository('Entities\Patientprofile');
$patient = $repository->findPatientByIdWithAssociations('555555557');
Run Code Online (Sandbox Code Playgroud)

确保你同时使用addSelectleftJoin进行预先加载.

  • @Wilt不幸的是,我发现`setFetchMode()`获取1级关联深度。我认为唯一的解决方案是“select”+“join”来加载所有关联。可以使用“setFetchMode()”吗? (2认同)

小智 9

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

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

例如

/**
 * @ManyToMany(targetEntity="Item", fetch="EAGER")
 */
private $items;
Run Code Online (Sandbox Code Playgroud)

  • 关于这种方法很糟糕的是,我希望根据上下文来加载.似乎无论你怎么称呼它,它总是会急切加载.我想唯一的另一种选择是使用DQL (8认同)

Max*_*nce 5

您可以使用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();
Run Code Online (Sandbox Code Playgroud)