Symfony Doctrine joining a one to many relationship

烂漫一生 提交于 2020-01-05 09:08:54

问题


I want to join two tables together to get retrieve all the entities in one search. I have a one to many relationship: Jedi and Member. One member group can have many Jedi's. I want to make a form to search by one entity and displays all of the information as a whole.

Example: Search for a Jedi by its assigned color -> retrieving name, age, gender, color, and rank.

Jedi.php:

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

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255)
 */
private $name;

/**
 * @var integer
 *
 * @ORM\Column(name="age", type="integer")
 */
private $age;

/**
 * @var string
 *
 * @ORM\Column(name="gender", type="string", length=255)
 */
private $gender;

/**
 *
 * @ORM\ManyToOne(targetEntity="Member", inversedBy="jedi")
 * @ORM\JoinColumn(name="member", referencedColumnName="id")
 */
private $member;

Member.php:

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

/**
 * @var string
 *
 * @ORM\Column(name="rank", type="string", length=255)
 */
private $rank;

/**
 * @var string
 *
 * @ORM\Column(name="color", type="string", length=255)
 */
private $color;

/**
 * @var integer
 * @ORM\OneToMany(targetEntity="Jedi", mappedBy="member")
 *
 */
protected $jedi;

In my JediRepository.php:

class JediRepository extends EntityRepository
{

public function findJediByColor($color) {

    $query = $this->getEntityManager()
        ->createQuery(
            'SELECT color, rank
             FROM YodaBundle:Member member
             JOIN member.jedi 
             WHERE member.color = :color'
        )->setParameter('color', $color);

    try {
        return $query->getSingleResult();
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }

 }
}

Now I am pretty sure I probably have the query join statement all wrong and I'm quite confused on how to to go about using it. Any help would be appreciated!


回答1:


You have a mistake in your code. Your query retrieve many rows but you get it as single row (getSingleResult()). As you can see in documentation (http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html#query-result-formats) getSingleResult() will throw an exception every time when many rows will satisfy your query. Also if you need all the columns of your entity you don't need to specify each in the query. You can just specify entity you want to retrieve:

$query = $this->getEntityManager()
    ->createQuery(
        'SELECT member, jedi
         FROM YodaBundle:Member member
         JOIN member.jedi 
         WHERE member.color = :color'
    )->setParameter('color', $color);

try {
    return $query->getResult();
} catch (\Doctrine\ORM\NoResultException $e) {
    return null;
}

Notice that in the Select statement I use member and jedi. In this case Doctrine will use eager joining (all data in one query). If you only need select members and for some of them retrieve jedis you can omit jedi in Select part of query.




回答2:


First of all you should move function findJediByColor to Member repository because the primary table is Member not Jedi.

Second you should use queryBuilder like this example below (inside MemberRepository). This will return One Member Object with array od Jedi's. Note that I use 'member_' as a primary alias.Somehow 'member' don't work (I don't now why).

public function findJediByColor($color) {

    $query = $this->createQueryBuilder('member_')
        ->where('member_.color = :color')
        ->join('member_.jedi', 'jedi')
        ->setParameter('color', $color)
        ->getQuery();

    try {
        return $query->getResult();
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }

}

If you realy want use DQL for that query it should look like this:

    $query = $this->getEntityManager()
        ->createQuery(
            'SELECT member_.color, member_.rank, jedi.name
            FROM YodaBundle:Member member_
            JOIN member_.jedi jedi
            WHERE member_.color = :color'
        )->setParameter('color', $color);



回答3:


You have not to create specifics requests to do things like this. It could be done simply :

  1. Using Eager loading in your oneToMany entity definition.

    /**
     * @var integer
     * @ORM\OneToMany(targetEntity="Jedi", mappedBy="member",fetch="EAGER")
     *
     */
     protected $jedi;
    
  2. Removing your public function findJediByColor($color) { in Jedi repository

  3. Using magic function repository in your controller directly like :

    $this->getDoctrine()
    ->getRepository('YourBundle:Member')
    ->findByColour($colour);
    

    or

    $this->getDoctrine()
    ->getRepository('YourBundle:Member')
    ->findByRank($rank);
    

    or

    $this->getDoctrine()
    ->getRepository('YourBundle:Member')
    ->findByJedi($jedi);
    

    or with multiple criteria

    $this->getDoctrine()
    ->getRepository('YourBundle:Member')
    ->findBy(array('colour' => $colour, 'rank' => $rank));
    


来源:https://stackoverflow.com/questions/23123691/symfony-doctrine-joining-a-one-to-many-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!