如何查询与Doctrine的多对多关系的反面

时间:2017-08-25 17:06:30

标签: php symfony doctrine many-to-many

我想知道哪些职业病包含在公司生产单位的所有医疗记录中。 MedicalRecord实体与DiseaseTypology有如下多种关系:

/**
 * AppBundle\Entity\HealthData\MedicalRecord
 *
 * @ORM\Table(name="medical_record")
 * @ORM\Entity(repositoryClass="MedicalRecordRepository")
 * @ORM\HasLifecycleCallbacks
 */
class MedicalRecord
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string $companyProductionUnitId
     *
     * @ORM\Column(name="company_production_unit_id", type="integer",nullable=true)
     */
    protected $companyProductionUnitId;

    /**
     * @var ArrayCollection $professionalDiseases
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\HealthData\Core\DiseaseTypology")
     * @ORM\JoinTable(name="medical_record_professional_disease",
     *      joinColumns={@ORM\JoinColumn(name="medical_record_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="professional_disease_id", referencedColumnName="id")}
     *      )
     *
     */
    protected $professionalDiseases;

在MedicalRecordReposity类中,我创建了以下方法:

public function getProfessionalDiseasesByProductionUnit($productionUnitId)
{
    $em = $this->getEntityManager();

    $repository = $em->getRepository('AppBundle:MedicalRecord');

    return $repository->createQueryBuilder('m')
        ->select('m.professionalDiseases')
        ->where('m.companyProductionUnitId = :productionUnitId')
        ->setParameter('productionUnitId', $productionUnitId)
        ->getQuery()
        ->getArrayResult();
}

但我收到错误:

  

[语义错误]第0行,第9行靠近'professionalDiseases':错误:无效的PathExpression。必须是StateFieldPathExpression。

如何查询多对多关系的反面?谢谢!

2 个答案:

答案 0 :(得分:1)

我不知道我是否能理解你想要的东西,但这是我的尝试:

class MedicalRecordRepository extends \Doctrine\ORM\EntityRepository
{
    public function getProfessionalDiseasesByProductionUnit($productionUnitId)
    {
        $qb = $this->createQueryBuilder('m');

        $qb
            ->select('m, pd')
            ->innerJoin('m.professionalDiseases', 'pd')
            ->where('m.companyProductionUnitId = :productionUnitId')
            ->setParameter('productionUnitId', $productionUnitId)
        ;

        return $qb->getQuery()->getArrayResult();
    }
}

说明:我认为您需要MedicalRecordDiseaseTypology之间的联接,为此,如果您有此设置(在您的两个实体中):

#Entity/MedicalRecord.php
private $companyProductionIUnitId;

/**
 * @var \AppBundle\Entity\DiseaseTypology
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\DiseaseTypology", mappedBy="medicalRecords")
 */
private $professionalDiseases;

首先,你必须有mappedBy选项,告诉学说关系的反面。

# Entity/DiseaseTypology.php
/**
 * @var \AppBundle\Entity\MedicalRecord
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\MedicalRecord", inversedBy="professionalDiseases")
 */
private $medicalRecords;

你必须有inversedBy选项来告诉学说这段关系的拥有方。

一旦我们澄清了这一点,让教条做与连接有关的事情,你只需要告诉它在哪个字段上进行连接。在我的示例中,MedicalRecordDiseaseTypology之间的关系是通过$professionalDiseases字段进行的。所以这个将成为联接的领域:

->innerJoin('m.professionalDiseases', 'pd') // this professionalDiseases is the $professionalDiseses from MedicalRecord entity

好的,我已经做了所有这些解释,因为我看到了你的查询方式,我觉得这不是正确的做法。

运行getProfessionalDiseasesByProductionUnit()方法后的结果如下:

enter image description here

答案 1 :(得分:1)

注意:使用getResult()而不是getArrayResult(),因为您获取实体(DiseaseTypology),而不是字段集

这里有两个选项:

  1. 建立关系MedicalRecord< => DiseaseTypology bidirectional See documentation。那么你的方法看起来很简单:

    public function getProfessionalDiseasesByProductionUnit($productionUnitId)
    {
        $em = $this->getEntityManager();
    
        $repository = $em->getRepository(DiseaseTypology::class);
    
        return $repository->createQueryBuilder('dt')
            ->select('dt')
            ->join('dt.medicalRecords', 'm')
            ->where('m.companyProductionUnitId = :productionUnitId')
            ->setParameter('productionUnitId', $productionUnitId)
            ->getQuery()
            ->getResult();
    }
    
  2. 保留现有数据库结构并在查询后添加一些逻辑

    public function getProfessionalDiseasesByProductionUnit($productionUnitId)
    {
        $em = $this->getEntityManager();
    
        $repository = $em->getRepository(MedicalRecord::class);
    
        $mediaRecords = $repository->createQueryBuilder('m')
            ->select('m, dt')
            //note: with this join all professionalDiseases will be loaded within one query for all MedicalRecords
            ->join('m.professionalDiseases', 'dt')
            ->where('m.companyProductionUnitId = :productionUnitId')
            ->setParameter('productionUnitId', $productionUnitId)
            ->getQuery()
            ->getResult();
    
        $professionalDiseases = [];
        foreach($mediaRecords as $mediaRecord) {
            foreach($mediaRecord->professionalDiseases as $professionalDisease) {
                $professionalDiseases[professionalDisease->id] = $professionalDisease;
            }
        }
    
        return $professionalDiseases;
    }