[英](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): 实际结果(类型名称 - 类别名称):
Expected result (type name - category name): 预期结果(类型名称 - 类别名称):
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.