dpg76975 2017-07-05 12:15
浏览 51

学说2 - 间接一对多关联

After a lot of searching for indirect associations, I only came up with this question. What I'd like to know is the exact opposite of that question, so I'm building up on it. Given the same entities:

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;
}

Is there any way to have a collection of all cities in a continent, without having to build a custom query every time, with a field in the same fashion as the countries collection, possibly via annotations or maybe dynamic mapping?

The only way I could think of is by overriding the find... methods in the Repository - which I'm not sure how exactly I could achieve adding the field - and then either looping over the countries and adding their cities to a new collection, or using a custom query entirely.

  • 写回答

1条回答 默认 最新

  • doudou3716 2017-07-05 13:54
    关注

    First a comment about your mapping. Your mapping is wrong here:

    inversedBy="countries" not inversedBy="country" and probably you want a column named continent_id instead of continentt_id

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

    And here it should be inversedBy="cities" not inversedBy="city":

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

    Consider using validation for your entity model, the validation tool that ships with doctrine ORM will help you to get these things correct.


    You can get such a result set by inner joining the countries with a certain continent.

    Inside your 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();
    }
    

    You can reuse the query and just pass a different value for continent to your $params array each time you want the cities for a different continent.

    This code is not tested, but I think it should work. Just leave a comment if you run into issues while testing this.


    You can also add methods like @Edwin suggested, but you have to realize that it will eagerly load all entities. This is killing for performance if you have a huge amount of rows in your tables (a lot of cities and countries). That is why a query in your repository would be better.


    Alternatively you can do this inside your entities by using criteria and collection filtering. You can read on how to do this here in the documentation chapter 8.8. Filtering Collections

    The advantage of using a filter is also well explained in the documentation:

    If the collection has not been loaded from the database yet, the filtering API can work on the SQL level to make optimized access to large collections.

    评论

报告相同问题?

悬赏问题

  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思