简体   繁体   中英

Cannot sort One-To-Many association with Doctrine

I am following the doctrine documentation about sort association: Ordering To-Many Associations

I have a category entity, it has many articles:

class Category
{
    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Article", mappedBy="category")
     * @ORM\OrderBy({"position"="ASC"})
     */
    private $articles;

}

article entity has a position field for sort:

class Article
{
    /**
     * @Gedmo\SortablePosition
     * @ORM\Column(name="position", type="integer", nullable=true)
     */
    private $position;
}

and get data from controller:

   /**
   * @Route("/zen", name="zen")
   */
  public function zen(){
    $category = $this->getDoctrine()->getRepository(Category::class);
    $categories = $category->createQueryBuilder('c')
      ->innerJoin('c.articles', 'a')
      ->addSelect('a')
      ->getQuery()->getResult();

    return $this->render('index/zen.html.twig', [
      'categories' => $categories
    ]);
  }

notice above, I add inner join and addSelect for avoid N+1 query problem.

in the template:

{% for c in categories %}
    {% for a in c.articles %}
      position: {{a.position}}, id: {{a.id}}
    {% endfor %}
{% endfor %}

the result should be ordered by position, like:

position: 1, id: 2
position: 2, id: 1
position: 3, id: 3
position: 4, id: 4

but actually ordered by id:

position: 2, id: 1
position: 1, id: 2
position: 3, id: 3
position: 4, id: 4

The Sortable behavior, when enabled, will attach a listener to the entity to update the SortablePosition property of all entries when one is updated, but will not affect query behavior.

You have to add the ordering to the query yourself or use the repository provided by the behavior by declaring it in your class:

/**
 * @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
 */
class Article
{
    /**
     * @Gedmo\SortablePosition
     * @ORM\Column(name="position", type="integer", nullable=true)
     */
    private $position;
}

Then you can get a queryBuilder with the predefined order via the repository (the entity will recieve the alias n ):

$categories = $category->getBySortableGroupsQueryBuilder()->innerJoin('n.articles', 'a');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM