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

Php 如何使用Doctrine2中的EntityManager检索具有所有关联的实体?,php,doctrine-orm,doctrine,Php,Doctrine Orm,Doctrine,我有一个具有多对多和一对多关联的简单实体。我知道用于获取相关关联的“连接”,这是解决我问题的手动方法 如何使用Doctrine2中的EntityManager获取实体及其所有关联?e、 g: $this->em ->getRepository('Entities\Patientprofile') ->findOneByuserid('5555557') ->获取所有关联(); 原则2使用代理类进行延迟加载,因此在使用对象之前,实际上不需要获取关联的数据。由于代理类继承自关联类,因此您可以像使用f

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

如何使用Doctrine2中的EntityManager获取实体及其所有关联?e、 g:

$this->em
->getRepository('Entities\Patientprofile')
->findOneByuserid('5555557')
->获取所有关联();

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

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

e、 g


您可以使用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();

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

$query = $em->createQuery("SELECT u FROM MyProject\User u");
$query->setFetchMode("MyProject\User", "address", "EAGER");
$query->execute();
如果要使用此获取模式动态加载所有关联,可以使用
doctor\ORM\Mapping\ClassMetadataInfo
getAssociationMappings()
方法,将实体名称作为参数传递给
ClassMetadataInfo
的构造函数,然后作为$assoc迭代返回的数组,并调用:

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

Doctrine2 setFetchMode不能与“EAGER”一起使用 我还尝试在查询中使用
setFetchMode
“急切地”获取关联实体,但以下操作似乎不起作用:

$query->setFetchMode("MyProject\User", "address", "EAGER");
当我跳进档案时。常量在条令\ORM\Mapping:ClassMetadataInfo中定义。当传递字符串时,由于以下原因,它将默认为
Mapping\ClassMetadata::FETCH\u LAZY

因此,设置相应的整数解决了问题:

$query->setFetchMode("MyProject\User", "address", 3);
或者在顶部声明类
使用条令\ORM\Mapping\ClassMetadata
,然后使用常量:

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

编辑: 由于这里似乎有很多关于如何正确获取关联的混淆,我将编辑我的答案,并添加一些关于如何使用存储库获取join的附加信息

有两种类型的联接:

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

  • 获取连接:除了使用常规连接之外:用于获取相关实体并将其包含在 询问

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

    我通常不使用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();
    }
    
    现在,您可以使用自定义存储库方法按id获取患者(例如“55557”),包括与患者文档和地址的关联:

    $repository = $this->em->getRepository('Entities\Patientprofile');
    $patient = $repository->findPatientByIdWithAssociations('555555557');
    
    确保您同时使用
    addSelect
    leftJoin
    来进行快速加载。

    面临同样的问题。 有必要拉出一个元素的所有父链。 $query->setFetchMode(EntityClass,“alias_in_entity”,3)get
    s仅1层深度,其他父级仅为代理。
    可以通过将实体类获取模式更改为“急切”来修复此问题。但如果由于某些原因(性能等)无法实现,则可以通过“动态”更改实体元数据来实现@wormhit

    例如:

    $query = $this->entityManager->createQueryBuilder()->select('fields')
                ->from(FormField::class, 'fields');
    $metadata = $this->entityManager->getClassMetadata(FormField::class);
    $metadata->setAssociationOverride('parent', ['fetch' => \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER]);
    
    return $query->getOneOrNullResult();
    

    这个方法最糟糕的一点是,我想根据上下文进行加载。似乎无论你怎么称呼它,它都将永远是渴望的负载。我想唯一的其他选择是使用DQL,这个方法的负载有多深?仅包含在对象U中的对象,这些类中的任何对象都将恢复为延迟加载?或者这个查询将加载任何链接到U的内容?@Michael.Lumley是的,它只会加载1级深度。有什么想法吗?唯一的解决方案是在DQL中手动加入所有关联?谢谢,这是我覆盖实体注释中设置的获取模式的正确方向。最后,我用
    $metadata=$this->getClassMetadata()在存储库公共方法中完成了这项工作(并在需要时调用它)$元数据->getAssociationMappings()在结果中循环并使用
    $metadata->setAssociationOverride($field,['fetch'=>$fetchMode])覆盖获取
    Doctrine2
    setFetchMode
    “EAGER”
    对我有效。我发现
    join
    select
    只适用于EAGER加载。无需调用
    setFetchMode()
    @Sithu问题是关于其他方式,而不是查询中的手动获取连接。我同意当您想在结果中加载关联时,选择+加入是常用的方法。@很遗憾,我发现
    setFetchMode()
    获取一级关联深度。我认为唯一的解决方案是选择
    加载所有关联。有没有可能使用
    setFetchMode()
    ?@Sithu我不这么认为。我必须说我自己从来没有使用过它,我发布了一个答案,因为我看到这里的人滥用(向方法传递了错误的参数)(我自己在测试方法时也犯了这个错误)。
    $repository = $this->em->getRepository('Entities\Patientprofile');
    $patient = $repository->findPatientByIdWithAssociations('555555557');
    
    $query = $this->entityManager->createQueryBuilder()->select('fields')
                ->from(FormField::class, 'fields');
    $metadata = $this->entityManager->getClassMetadata(FormField::class);
    $metadata->setAssociationOverride('parent', ['fetch' => \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER]);
    
    return $query->getOneOrNullResult();