简体   繁体   English

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

[英](Doctrine ORM) How to order SELECT by many-to-one relationship

I have a database with types and categories (among other, unrelated things). 我有一个包含类型类别的数据库(以及其他不相关的东西)。 Types have a many-to-one relationship with categories . 类型类别具有多对一关系。 What I want is to select all type rows, ordered first by category name and then by type weight and lastly by type name (all ascending). 我想要的是选择所有类型的行,首先按类别名称排序,然后按类型权重排序,最后按类型名称排序(全部升序)。 The critical part is that I want all the types with the same category to be grouped together in the result. 关键部分是我希望所有具有相同类别的类型在结果中组合在一起。 Being the SQL neophyte that I am, I thought a simple join statement followed by appropriate order by statements would be sufficient. 作为我的SQL新手,我认为一个简单的连接语句后跟适当的语句顺序就足够了。 I was wrong. 我错了。 The result I'm getting makes no sense to me. 我得到的结果对我来说毫无意义。

Actual result (type name - category name): 实际结果(类型名称 - 类别名称):

  1. Aircraft Landing Strut - Aircraft 飞机着陆支柱 - 飞机
  2. Aicraft Rotor Blade - Aircraft Aicraft转子叶片 - 飞机
  3. Aircraft Wing - Aircraft 飞机机翼 - 飞机
  4. Bicycle Frame - Riding Cycles 自行车车架 - 骑行周期
  5. Boat Bow - Watercraft 船弓 - 船只
  6. Boat Cargo Deck - Watercraft 船货船甲板 - 船只
  7. Boulder Bottom - Rocks 博尔德底部 - 岩石
  8. Boulder Top - Rocks 博尔德顶部 - 岩石
  9. Bowed Element - Others 鞠躬元素 - 其他
  10. Brick 1x1 w/Juice Carton Print - Bricks Printed 砖1x1瓦特/果汁纸盒打印 - 砖打印
  11. Brick 1x1 w/Milk Carton Print - Bricks Printed 砖1x1瓦特/牛奶纸箱打印 - 砖打印
  12. Car Wash Brush Holder - Others 洗车刷架 - 其他
  13. [etc.] [等等。]

Expected result (type name - category name): 预期结果(类型名称 - 类别名称):

  1. Aircraft Landing Strut - Aircraft 飞机着陆支柱 - 飞机
  2. Aicraft Rotor Blade - Aircraft Aicraft转子叶片 - 飞机
  3. Aircraft Wing - Aircraft 飞机机翼 - 飞机
  4. Brick 1x1 w/Juice Carton Print - Bricks Printed 砖1x1瓦特/果汁纸盒打印 - 砖打印
  5. Brick 1x1 w/Milk Carton Print - Bricks Printed 砖1x1瓦特/牛奶纸箱打印 - 砖打印
  6. Bowed Element - Others 鞠躬元素 - 其他
  7. Car Wash Brush Holder - Others 洗车刷架 - 其他
  8. Bicycle Frame - Riding Cycles 自行车车架 - 骑行周期
  9. Boulder Bottom - Rocks 博尔德底部 - 岩石
  10. Boulder Top - Rocks 博尔德顶部 - 岩石
  11. Boat Bow - Watercraft 船弓 - 船只
  12. Boat Cargo Deck - Watercraft 船货船甲板 - 船只
  13. [etc.] [等等。]

There are over 2,000 type rows, so the above lists are obviously very truncated. 有超过2,000种类型的行,因此上面的列表显然是非常截断的。 There are no errors. 没有错误。 It's probably also important that the results are paginated (which has been working perfectly). 对结果进行分页(一直运行良好)可能也很重要。

I'm using Doctrine 2.5.x with my own content management system. 我正在使用Doctrine 2.5.x和我自己的内容管理系统。 In the repository for the type entity I'm using QueryBuilder to construct the query as follows (the max result is a global setting and the first result is calculated outside the repository based on the current page number): 在类型实体的存储库中,我使用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();

The resultant SQL statement is as follows: 生成的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

The type entity is set up like this (with irrelevant fields ommitted): 类型实体设置如下(省略了不相关的字段):

/**
 * @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;

}

And the category entity is set up like this: 类别实体设置如下:

/**
 * @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 extends DefaultRepository which extends Doctrine's EntityRepository . TypeRepository扩展了DefaultRepository ,它扩展了Doctrine的EntityRepository

The weird ordering of the result was caused by the fact that the category name column is sometimes null (when displayed the name falls back to the transformed contents of the slug column, a change I'd completely forgotten about). 结果的奇怪排序是由于类别name列有时为null (当显示时名称会回落到slug列的转换内容,这是我完全忘记的更改)。 Therefore simply changing the first order-by statement to be c.slug instead solves the problem. 因此,只需将第一个order-by语句更改为c.slug解决问题。 D'oh! D'哦!

So remember, ordering by columns which can be null will cause strange results! 所以请记住,按列排序可能为空将导致奇怪的结果!

Have you tried 你有没有尝试过

$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');
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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