Доктрина: выберите таблицу, которой не управляет доктрина

Используя Doctrine QueryBuilder, я хочу выполнить запрос, который в родном SQL выглядит так:

`SELECT image FROM image i INNER JOIN about_images a ON i.id = a.image_id`;

Результат в DQL следующий:

ImageRepository.php:

return $this->createQueryBuilder('i')
        ->select('i')
        ->innerJoin('about_images', 'a', 'WITH', 'i.id = a.imageId')
        ->getQuery()
        ->getResult();

Где image — сущность, а about_images — таблица соединения (результат отношения @ManyToMany). Однако я получаю сообщение об ошибке, что about_images не определен, что имеет смысл, поскольку он не управляется доктриной.

О странице.php (т. е. сущность, в которой создается таблица соединений)

  /**
     * @var Image[]|ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity = "App\Entity\Image", cascade = {"persist", "remove"})
     * @ORM\JoinTable(name = "about_images",
     *     joinColumns = {@ORM\JoinColumn(name = "about_id", referencedColumnName = "id")},
     *     inverseJoinColumns = {@ORM\JoinColumn(name = "image_id", referencedColumnName = "id", unique=true)})
   */
    private $images;

Поля из изображения:

    /**
     * @var int
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(type = "string", length=255)
     */
    private $image;

    /**
     * @var File
     *
     * @Vich\UploadableField(mapping = "collection_images", fileNameProperty = "image")
     * @Assert\File(maxSize = "150M", mimeTypes = {"image/jpeg", "image/jpg", "image/png", "image/gif"},
     *     mimeTypesMessage = "The type ({{ type }}) is invalid. Allowed image types are {{ types }}")
     */
    private $imageFile;

    /**
     * @var string
     *
     * @ORM\Column(type = "string", length=255, nullable=true)
     */
    private $imageAlt;

    /**
     * @var DateTime
     *
     * @ORM\Column(type = "datetime")
     */
    private $updatedAt;

    /**
     * @var string
     *
     * @ORM\Column(type = "string", nullable=true)
     */
    private $alt;

Как я могу решить эту проблему? Результаты должны быть объектами Image.

Вы можете использовать собственный запрос (SQL), а затем использовать RSM для сопоставления полей, возвращаемых результатом, с вашей сущностью. См.: doctrine-project.org/projects/doctrine-orm/en/2.6/reference/‌​… Не стесняйтесь следить, если документы неясны или вы застряли в реализации этого, и я могу написать более подробный ответ.

dbrumann 31.01.2019 15:26

@dbrumann За документацией действительно непросто следить, и я не смог найти четких примеров в Интернете. Я был бы признателен за некоторые рекомендации. Дайте мне знать, если вам нужна дополнительная информация о моем объекте Image. Спасибо.

Helenesh 31.01.2019 15:53

Пожалуйста, опубликуйте свой класс App\Entity\Image (свойство about_pages). Кстати, это можно сделать... $entityManager->getRepository(AboutPage::class)->createQuery‌​Builder("a")->join("‌​a.images", "i")

SilvioQ 31.01.2019 16:00

@SilvioQ Я обновил свой вопрос кодом, который вы запросили. В моем объекте aboutPage нет свойства Image. На изображения ссылаются через таблицу соединений, поэтому мне нужен доступ к этой таблице соединений.

Helenesh 31.01.2019 16:45

ммм... Image::class ничего не знает о AboutPage::class... как насчет $entityManager->getRepository(AboutPage::class)->createQuery‌​Builder("a")->join("‌​a.images", "i")->select("a,i")

SilvioQ 31.01.2019 17:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
2
5
1 080
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете написать собственный SQL, а затем сопоставить выходные данные с вашими объектами с помощью ResultSetMapper.

Для вашего примера это может выглядеть примерно так в вашем классе репозитория:

public function findImagesWithAboutImages()
{
    $sql = 'SELECT i.* FROM image i INNER JOIN about_images a ON i.id = a.image_id';
    $entityManager = $this->getEntityManager();

    $mappingBuilder = new ResultSetMappingBuilder($entityManager);
    $mappingBuilder->addRootEntityFromClassMetadata(Image::class, 'i');

    $query = $entityManager->createNativeQuery($sql, $mappingBuilder);
    // If you want to set parameters e.g. you have something like WHERE id = :id you can do it on this query object using setParameter()

    return $query->getResult();
}

Если вам нужны связанные данные, вам нужно будет добавить их в предложение select с псевдонимом, а затем использовать $mappingBuilder->addJoinedEntityFromClassMetadata(), чтобы назначить эти поля объединенному объекту, как и выше с корневым объектом.

Ваши аннотации в вашей сущности уже определяют, как каждое поле сопоставляется со свойством и какой у него тип, поэтому в основном вы должны получить массив изображений-сущностей со всем (кроме связанных сущностей), загруженным для использования.

Есть идеи, почему этот код выдает TableNotFoundException: Unknown table image? Протестировал его с помощью необработанного запроса, и он дал мне правильные результаты без исключения. Классы также правильно импортированы. Спасибо за старания.

Helenesh 31.01.2019 18:21

Я пропустил псевдоним в FROM, возможно, это он. Попробуйте SELECT i.* и также в addRootEntityFromClassMetadata замените image на i. Я также обновил ответ.

dbrumann 31.01.2019 18:49

Работал как шарм. Спасибо.

Helenesh 31.01.2019 19:25

Не совсем ясен пример sql с предоставленным вами кодом, но если у вас есть отношение, определенное в ваших объектах, вы можете присоединиться к ним с помощью построителя запросов, просто указав поле отношения объекта, поэтому я думаю, что это должно работать

return $this->createQueryBuilder('i')
    ->select('i')
    ->innerJoin('i.images', 'a')
    ->getQuery()
    ->getResult();

Поскольку вы уже определили свои отношения в своих сущностях, Doctrine знает, как соединить ваши таблицы, поэтому вам просто нужно указать имя поля отношения и псевдоним.

И всегда помните, что вы должны использовать имя поля в своей сущности (обычно cameCasedStyle), а не имя столбца в таблицах вашей базы данных (обычно змея_cased_style).

Другие вопросы по теме