(Doctrine ORM)如何通过多对一关系订购SELECT

时间:2019-04-02 20:04:08

标签: php mysql doctrine-orm

我有一个包含 types categories 的数据库(以及其他无关的东西)。 类型类别有多对一的关系。我想要的是选择所有类型的行,首先按类别名称排序,然后按类型权重排序,最后按类型名称排序(全部升序)。关键部分是我希望将具有相同类别的所有类型归为一组。作为我的SQL新手,我认为简单的join语句,然后按适当的by语句顺序就足够了。我错了。我得到的结果对我来说毫无意义。

实际结果(类型名称-类别名称):

  1. 飞机降落支柱-飞机
  2. 飞机转子叶片-飞机
  3. 飞机机翼-飞机
  4. 自行车车架-骑行车
  5. 船Bow-船只
  6. 船货甲板-船只
  7. 冰山底部-岩石
  8. 上衣-岩石
  9. 弓形元素-其他
  10. 带果汁纸盒打印的砖1x1-已打印的砖
  11. 1x1瓦楞纸箱砖印刷-砖头印刷
  12. 洗车刷架-其他
  13. [etc。]

预期结果(类型名称-类别名称):

  1. 飞机降落支柱-飞机
  2. 飞机转子叶片-飞机
  3. 飞机机翼-飞机
  4. 带果汁纸盒打印的砖1x1-已打印的砖
  5. 1x1瓦楞纸箱砖印刷-砖头印刷
  6. 弓形元素-其他
  7. 洗车刷架-其他
  8. 自行车车架-骑行车
  9. 冰山底部-岩石
  10. 上衣-岩石
  11. 船Bow-船只
  12. 船货甲板-船只
  13. [etc。]

有超过2,000个类型行,因此上面的列表显然被截断了。没有错误。对结果分页(效果很好)可能也很重要。

我在自己的内容管理系统上使用Doctrine2.5.x。在类型实体的存储库中,我使用QueryBuilder来构造查询,如下所示(最大结果是全局设置,并且第一个结果是根据当前页码在存储库外部计算的):

$qb = $this->createQueryBuilder('t');

$qb->select('t, c'); // omitting this does not change the result
$qb->join('t.category', 'c');
$qb->addOrderBy('c.name', 'ASC'); // this does not work as expected
$qb->addOrderBy('t.weight', 'ASC');
$qb->addOrderBy('t.name', 'ASC');
$qb->setMaxResults(20);
$qb->setFirstResult(0);

return $qb->getQuery()->getResult();

结果SQL语句如下:

SELECT b0_.ID AS ID_0, b0_.weight AS weight_1, b0_.name AS name_2, b0_.number AS number_3, b0_.name_alt AS name_alt_4, b0_.note AS note_5, b1_.ID AS ID_12, b1_.slug AS slug_13, b1_.name AS name_14, b1_.`desc` AS desc_15, b0_.cat_id AS cat_id_16 FROM types b0_ INNER JOIN categories b1_ ON b0_.cat_id = b1_.ID ORDER BY b1_.name ASC, b0_.weight ASC, b0_.name ASC LIMIT 20 OFFSET 0

类型实体设置如下(忽略无关字段):

/**
 * @Entity(repositoryClass="Nevermind\Repository\TypeRepository")
 * @Table(name="types", options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"})
 */
class Type {

    /**
     * @Id
     * @Column(type="integer", name="ID")
     * @GeneratedValue
     */
    protected $id;

    /**
     * @ManyToOne(targetEntity="Category", inversedBy="types", fetch="EAGER")
     * @JoinColumn(name="cat_id", referencedColumnName="ID")
     */
    protected $category;

    /**
     * @Column(type="integer")
     */
    protected $weight = 0;

    /**
     * @Column(type="string", unique=true)
     */
    protected $name = '';

    /**
     * @Column(type="string", unique=true, length=12)
     */
    protected $number = '';

    /**
     * @Column(type="string", nullable=true)
     */
    protected $name_alt;

    /**
     * @Column(type="text", nullable=true)
     */
    protected $note;

}

类别实体的设置如下:

/**
 * @Entity(repositoryClass="Nevermind\Repository\DefaultRepository")
 * @Table(name="categories", options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"})
 */
class Category {

    /**
     * @Id
     * @Column(type="integer", name="ID")
     * @GeneratedValue
     */
    protected $id;

    /**
     * @Column(type="string", unique=true)
     */
    protected $slug = '';

    /**
     * @Column(type="string", nullable=true)
     */
    protected $name;

    /**
     * @Column(type="text", name="`desc`", nullable=true)
     */
    protected $desc;

    /**
     * @OneToMany(targetEntity="Type", mappedBy="category", fetch="EXTRA_LAZY", cascade={"persist", "remove"})
     * @OrderBy({"weight"="ASC", "name"="ASC"})
     */
    protected $types;

}

TypeRepository扩展了DefaultRepository,扩展了学说的EntityRepository

2 个答案:

答案 0 :(得分:1)

结果的怪异排序是由于以下事实造成的:类别name列有时为null(在显示时,名称退回到slug列的转换后的内容中,我完全忘记的更改)。因此,只需将第一个order-by语句更改为c.slug即可解决问题。噢!

所以请记住,按可以为null的列排序会导致奇怪的结果!

答案 1 :(得分:-1)

您尝试过

$qb->select('t, c');
...
$qb->orderBy('c.name', 'ASC'); // orderBy not addOrderBy for the first clause
$qb->addOrderBy('t.weight', 'ASC');
$qb->addOrderBy('t.name', 'ASC');
...