(Doctrine ORM) Как заказать SELECT по отношениям многие-к-одному - PullRequest
4 голосов
/ 02 апреля 2019

У меня есть база данных с типами и категориями (среди прочих, не связанных между собой вещей). Типы имеют отношение "многие к одному" с категориями .Я хочу выбрать все строки типа, упорядоченные сначала по имени категории, а затем по весу типа и, наконец, по имени типа (все по возрастанию).Критическая часть состоит в том, что я хочу, чтобы все типы с той же категорией были сгруппированы в результате.Будучи неофитом SQL, которым я являюсь, я подумал, что достаточно простого оператора соединения с последующим соответствующим порядком операторов.Я был неправ.Результат, который я получаю, не имеет для меня никакого смысла.

Фактический результат (имя типа - название категории):

  1. Стойка посадки самолета - Самолет
  2. Aicraft Rotor Blade - Самолет
  3. Крыло самолета - Самолет
  4. Рама велосипеда - Езда на велосипеде
  5. Лук для лодки - Водный транспорт
  6. Грузовая палуба для лодки - Водный корабль
  7. Нижний валун - Скалы
  8. Верх валуна - Скалы
  9. Согнутый элемент - Другие
  10. Кирпич 1x1 с принтом картонной упаковки сока - Печатные кирпичи
  11. Кирпич 1x1 с печатью на молочной коробке - Печатный кирпич
  12. Щетка для мойки автомобилей - Другие
  13. [и т. Д.]

Ожидаемый результат (название типа - название категории):

  1. Стойка посадки самолета - Самолет
  2. Лезвие ротора Aicraft - Самолет
  3. Крыло самолета - Aircrв кормовой части
  4. Кирпич 1x1 с печатью сока - Кирпичи с печатью
  5. Кирпич 1x1 с печатью с молоком - Кирпичи с печатью
  6. Согнутый элемент - Другие
  7. Щетка для автомойки - Другие
  8. Рамка для велосипеда - Езда на велосипеде
  9. Нижний валун - Скалы
  10. Верхний валун - Скалы
  11. Лодочный нос - Водный транспорт
  12. Палубный грузовой отсек - Водный транспорт
  13. [и т. Д.]

Имеется более 2000 строк типов, поэтому приведенные выше списки, очевидно, очень усечены.Там нет ошибок.Вероятно, также важно, чтобы результаты были разбиты на страницы (что работало отлично).

Я использую Doctrine 2.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 ]

1 голос
/ 19 апреля 2019

Странный порядок результата был вызван тем фактом, что столбец категории name иногда равен null (при отображении имя возвращается к преобразованному содержимому столбца slug.забыли про).Поэтому простое изменение первого оператора order-by на c.slug вместо этого решает проблему.О'оо!

Помните, что упорядочение по столбцам, которые могут быть нулевыми, приведет к странным результатам!

0 голосов
/ 03 апреля 2019

Вы пробовали

$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');
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...