学说2 - 间接一对多关联

时间:2017-07-05 12:15:03

标签: php symfony doctrine-orm

经过大量搜索间接关联后,我才提出this question。我想知道的是与这个问题正好相反,所以我要积累它。给定相同的实体:

class Continent {
    /**
    * @ORM\Id
    * @ORM\Column(type="integer", name="id")
    * @ORM\GeneratedValue(strategy="IDENTITY")
    */
    private $id;

    /**
    * @ORM\OneToMany(targetEntity="AppBundle\Entity\Country", mappedBy="continent")
    */
    private $countries;
}


class Country {
    /**
    * @ORM\Id
    * @ORM\Column(type="integer", name="id")
    * @ORM\GeneratedValue(strategy="IDENTITY")
    */
    private $id;

    /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Continent", inversedBy="countries")
    * @ORM\JoinColumn(name="continent_id", referencedColumnName="id")
    */
    private $continent;

    /**
    * @ORM\OneToMany(targetEntity="AppBundle\Entity\City", mappedBy="country")
    */
    private $cities;
}

class City {
    /**
    * @ORM\Id
    * @ORM\Column(type="integer", name="id")
    * @ORM\GeneratedValue(strategy="IDENTITY")
    */
    private $id;

    /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Country", inversedBy="cities")
    * @ORM\JoinColumn(name="country_id", referencedColumnName="id")
    */
    private $country;
}

有没有办法拥有一个大陆所有城市的集合,而不必每次都建立一个自定义查询,一个字段与国家集合相同,可能通过注释或动态映射?

我能想到的唯一方法是覆盖存储库中的find...方法 - 我不确定如何才能实现添加字段 - 然后循环遍历各个国家/地区并添加他们的城市是一个新的集合,或完全使用自定义查询。

1 个答案:

答案 0 :(得分:1)

首先评论您的映射。你的映射在这里是错误的:

RuntimeException不是inversedBy="countries",您可能想要一个名为inversedBy="country"的列,而不是continent_id

continentt_id

此处应/** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Continent", inversedBy="countries") * @ORM\JoinColumn(name="continent_id", referencedColumnName="id") */ private $continent; 而不是inversedBy="cities"

inversedBy="city"

考虑对您的实体模型使用验证,与教条ORM一起提供的验证工具将帮助您正确理解这些内容。

你可以通过内部加入某个特定大陆的国家来获得这样的结果。

/** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Country", inversedBy="cities") * @ORM\JoinColumn(name="country_id", referencedColumnName="id") */ private $country; 内:

CityRepository

您可以重复使用该查询,只需在每次希望不同大陆的城市时,将大陆的其他值传递给use Doctrine\ORM\Query\Expr\Join; //... public function findCitiesByContinent($params){ $queryBuilder = $this->createQueryBuilder('c') ->innerJoin('c.country', 'cc', Join::WITH, 'cc.continent = :continent') ->setParameter('continent', $params['continent']); $query = $queryBuilder->getQuery(); return $query->getResult(); } 数组。

此代码未经过测试,但我认为它应该可行。如果您在测试时遇到问题,请发表评论。

您还可以添加@Edwin建议的方法,但您必须意识到它会急切地加载所有实体。如果您的表(很多城市和国家/地区)中有大量行,这会导致性能下降。这就是为什么您的存储库中的查询会更好。

或者,您可以使用条件和集合过滤在实体内执行此操作。您可以在文档章节 8.8. Filtering Collections

中阅读有关如何执行此操作的信息

在文档中也很好地解释了使用过滤器的优点:

  

如果尚未从数据库加载集合,则过滤API可以在SQL级别上工作,以便对大型集合进行优化访问。