Доктрина делает слишком много запросов

У меня есть несколько объектов, и когда я делаю findAll, у меня есть только 1 запрос, за исключением одного объекта.

/**
 * @ORM\Entity(repositoryClass = "App\Repository\PropertyRepository")
 * @ORM\Table(name = "property")
 */
class Property
{
/**
 * @ORM\Id()
 * @ORM\GeneratedValue()
 * @ORM\Column(type = "integer")
 * @Assert\Type("integer")
 * @var int
 */
private $id;

/**
 * @ORM\Column(type = "string", length=255)
 * @Assert\NotBlank
 * @Assert\Choice({"Appartement", "Maison", "Garage", "Bureau", "Château", "Commerce"})
 * @var string
 */
private $propertyCategory;

/**
 * @ORM\Column(type = "string", length=255)
 * @Assert\NotBlank
 * @Assert\Type("string")
 * @var string
 */
private $uniqueName;

/**
 * @ORM\Column(type = "string", length=255)
 * @Assert\NotBlank
 * @Assert\Type("string")
 * @var string
 */
private $address;

/**
 * @ORM\Column(type = "string", length=255)
 * @Assert\NotBlank
 * @Assert\Type("string")
 * @var string
 */
private $city;

/**
 * @ORM\Column(type = "integer")
 * @Assert\NotBlank
 * @Assert\Type("integer")
 * @Assert\Length(min = 5, minMessage = "Ce champ doit contenir 5 chiffres")
 * @Assert\Length(max = 5, maxMessage = "Ce champ doit contenir 5 chiffres")
 * @var int
 */
private $zipCode;

/**
 * @ORM\Column(type = "string", length=255)
 * @Assert\NotBlank
 * @Assert\Country
 * @var string
 */
private $country;

/**
 * @ORM\Column(type = "integer")
 * @Assert\NotBlank
 * @Assert\Type("integer")
 * @var string
 */
private $surfaceInSquareMeter;

/**
 * @ORM\Column(type = "integer")
 * @Assert\NotBlank
 * @Assert\Type("integer")
 * @var int
 */
private $numberOfPiece;

/**
 * @ORM\Column(type = "text", nullable=true)
 * @Assert\Type("string")
 * @var string
 */
private $description;

/**
 * @ORM\Column(type = "string", length=255)
 * @Assert\NotBlank
 * @Assert\Choice({"Meublé", "Non meublé"})
 * @var string
 */
private $rentalCategory;

/**
 * @ORM\Column(type = "float")
 * @Assert\NotBlank
 * @Assert\Type("float")
 * @var float
 */
private $rentExcludingCharges;

/**
 * @ORM\Column(type = "float")
 * @Assert\NotBlank
 * @Assert\Type("float")
 * @var float
 */
private $charges;

/**
 * @ORM\Column(type = "float")
 * @Assert\NotBlank
 * @Assert\Type("float")
 * @var float
 */
private $purchasePrice;

/**
 * @ORM\ManyToOne(targetEntity = "App\Entity\User", inversedBy = "properties")
 * @JoinColumn(name = "user_property_id", referencedColumnName = "id", onDelete = "CASCADE")
 */
private $userProperty;

/**
 * @ORM\ManyToMany(targetEntity = "App\Entity\Equipment", mappedBy = "equipment")
 */
private $equipment;

/**
 * @ORM\ManyToMany(targetEntity = "App\Entity\Lessee", mappedBy = "lessee")
 */
private $lessees;

/**
 * @ORM\Column(type = "string", length=255, nullable=true)
 * @Assert\File(
 *     maxSize = "2000k",
 *     mimeTypes = {"application/pdf", "application/x-pdf"},
 *     mimeTypesMessage = "Choisisez un fichier PDF"
 * )
 */
private $pdfFile;

Я не показываю вам геттеры/сеттеры, потому что это более 500 строк, но я их сгенерировал.

Doctrine выполняет 1 запрос для каждого свойства. Чтобы решить мою проблему, я попытался сделать это:

/**
 * @param User $user
 * @return array
 */
public function findPropertyByUser(User $user): array
{
    $qb = $this->createQueryBuilder('p')
        ->andWhere('p.userProperty = :user')
        ->setParameter('user', $user)
        ->orderBy('p.id', 'ASC')
        ->getQuery();
    return $qb->execute();
}

но это ничего не меняет, я тоже пытаюсь использовать findBy, но это ничего не меняет. Может ли кто-нибудь сказать мне, откуда моя проблема?

РЕДАКТИРОВАТЬ: согласно комментариям, это, вероятно, проблема n+1,

Я пробовал разные вещи, но не нашел решения, вот мой фактический метод:

/**
 * @param User $user
 * @return array
 */
public function findPropertyByUser(User $user): array
{
    $qb = $this->createQueryBuilder('p')
        ->andWhere('p.userProperty = :user')
        ->setParameter('user', $user)
        ->orderBy('p.id', 'ASC')
        ->innerJoin('p.userProperty', 'u')
        ->addSelect('u')
        ->getQuery();
    return $qb->execute();
}

Запрос Ну наконец то поступает с моей точки зрения

{% if properties is defined %}
            {% for property in properties %}

                    {% set emails = [property.userProperty.email] %}
                    {% for lessee in property.lessees.values %}
                        {% set emails = emails|merge([lessee.email]) %}
                    {% endfor %}

                    {% if app.user.email in emails %}
                        <tr>
                            <td>{{ property.propertyCategory }}</td>
                            <td>{{ property.uniqueName }}</td>
                            <td>{{ property.address }}</td>
                            <td>{{ property.city }}</td>
                            <td>{{ property.zipCode }}</td>
                            <td>{{ property.rentExcludingCharges }} €</td>
                            <td>{{ property.charges }} €</td>
                            <td>{{ property.purchasePrice }} €</td>
                            <td>
                                <a href = "{{ path('property_show', {'id': property.id}) }}">Voir</a>
                                {% if is_granted('ROLE_USER') %}
                                    <a href = "{{ path('property_edit', {'id': property.id}) }}"><i class = "fas fa-edit"></i> édition</a>
                                {% endif %}
                            </td>
                        </tr>
                    {% endif %}
            {% endfor %}
        {% else %}
            <tr>
                <td colspan = "16">Vous n'avez pas enregistré de propriétés</td>
            </tr>
        {% endif %}

Начало решения У меня на один запрос меньше:

/**
 * @param User $user
 * @return array
 */
public function findPropertyByUser(User $user): array
{
    $qb = $this->createQueryBuilder('p')
        ->andWhere('p.userProperty = :user')
        ->setParameter('user', $user)
        ->orderBy('p.id', 'ASC')
        ->innerJoin('p.lessees', 'l')
        ->getQuery();
    return $qb->execute();
}

Это проблема N+1, я думаю, это поможет вам: symfonycasts.com/screencast/doctrine-relations/join-n-plus-o‌​ne

ElliotBrl 09.04.2019 10:59

Большое спасибо за то, что рассказали мне, в чем моя проблема, но я пробовал разные вещи и не нашел решения

Tom Paler 09.04.2019 11:56

Можете ли вы показать мне запрос от профилировщика и один из дополнительных запросов?

ElliotBrl 09.04.2019 13:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
3
121
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вам нужно левое соединение, например:

/**
 * @param User $user
 * @return array
 */
public function findPropertyByUser(User $user): array
{
    $qb = $this->createQueryBuilder('p')
        ->leftJoin('p.lessees', 'l')
        ->andWhere('p.userProperty = :user OR l.email = :userEmail')
        ->setParameter('user', $user)
        ->setParameter('userEmail', $user->getEmail())
        ->orderBy('p.id', 'ASC')
        ->getQuery();

    return $qb->execute();
}

и в представлении удалите все об электронной почте:

{% if properties is defined %}
            {% for property in properties %}
                <tr>
                    <td>{{ property.propertyCategory }}</td>
                    <td>{{ property.uniqueName }}</td>
                    <td>{{ property.address }}</td>
                    <td>{{ property.city }}</td>
                    <td>{{ property.zipCode }}</td>
                    <td>{{ property.rentExcludingCharges }} €</td>
                    <td>{{ property.charges }} €</td>
                    <td>{{ property.purchasePrice }} €</td>
                    <td>
                        <a href = "{{ path('property_show', {'id': property.id}) }}">Voir</a>

                        {% if is_granted('ROLE_USER') %}
                            <a href = "{{ path('property_edit', {'id': property.id}) }}"><i class = "fas fa-edit"></i> édition</a>
                        {% endif %}
                    </td>
                </tr>
            {% endfor %}
        {% else %}
            <tr>
                <td colspan = "16">Vous n'avez pas enregistré de propriétés</td>
            </tr>
        {% endif %}

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