Symfony4.1 Doctrine ManyToMany Уменьшить количество запросов

Я работаю над проектом. Сущность — это блог, категория, теги. Блог и теги находятся в отношениях ManyToMany. Мой запрос к репозиторию для получения данных по фильтру тегов.

КОД1:

/**
 * @return BlogPost[]
 */
public function getAllActivePostsByTags($value, $order = "DESC", $currentPage = 1, $limit = 10)
{
    $query = $this->createQueryBuilder('p')
        // ->select('p','t')
        ->innerJoin('p.blogTags', 't')
        ->where('t.slug = :val')
        ->setParameter('val', $value)
        ->orderBy('p.id', $order)
        ->getQuery();

    $paginator = $this->paginate($query, $currentPage, $limit);

    return $paginator;
}

Этот код работает нормально. Все теги (количество тегов в посте) отображаются правильно. Но No of DB Query равно 14. Затем, когда я раскомментирую select как это,

КОД2:

/**
 * @return BlogPost[]
 */
public function getAllActivePostsByTags($value, $order = "DESC", $currentPage = 1, $limit = 10)
{
    $query = $this->createQueryBuilder('p')
        ->select('p','t')
        ->innerJoin('p.blogTags', 't')
        ->where('t.slug = :val')
        ->setParameter('val', $value)
        ->orderBy('p.id', $order)
        ->getQuery();

    $paginator = $this->paginate($query, $currentPage, $limit);

    return $paginator;
}

Количество запросов – 9. Но количество тегов в публикации – только одно (все теги одного сообщения не отображаются).

Для ясности:

  • Он отображает весь список BlogPost.
  • Но не все теги поста.
  • Отображается только один тег на сообщение.

Вопрос. Верен ли code1 (количество запросов к БД = 14) или мне нужно немного подправить, чтобы уменьшить количество попаданий в БД. Пожалуйста, помогите мне в этом.


person Sudhakar Krishnan    schedule 20.11.2018    source источник


Ответы (2)


Это ожидаемое поведение в обоих случаях.

Случай 1) Вы просто выбираете объекты BlogPost. Таким образом, вы указываете доктрине извлекать все сообщения блога, которые имеют тег BlogTag со значением slug = value. Сгенерированный SQL-запрос возвращает только значения столбцов из таблицы blog_post и, таким образом, заполняет только возвращаемые объекты BlogPost, но не заполняет коллекцию BlogTags внутри каждого сообщения BlogPost.

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

Именно поэтому в данном случае вы получаете больше запросов.

Случай 2) Вы также выбираете отфильтрованные сущности BlogTag, и доктрина помещает только этот отфильтрованный BlogTag в каждую коллекцию BlogPost.

Когда вы пытаетесь получить доступ к BlogTags сообщения BlogPost, вы получаете отфильтрованный тег, который соответствует условию в построителе запросов.

Чтобы заставить доктрину «перезагрузить» данные из базы данных, вы должны обновить объект blogPost:

 $em->refresh($blogPost);

а также включить параметр обновить на каскадные операции определения отношения:

@OneToMany(targetEntity="BlogTag", mappedBy="post", cascade={"refresh"})

Использованная литература:

person Jannes Botis    schedule 16.12.2018

Спасибо @Jannes Botis за обновление. Но в моем случае сам код неверен. Там нужно небольшое изменение в нем.

BlogTags.php

/**
 * @ORM\ManyToMany(targetEntity="BlogPost", mappedBy="blogTags")
 */
private $blogPosts;

BlogPost.php

/**
 * @var Collection|BlogTags[]
 *
 * @ORM\ManyToMany(targetEntity="BlogTags", inversedBy="blogPosts", cascade={"refresh"})
 * @ORM\JoinTable(
 *  name="fz__blog_n_tag",
 *  joinColumns={
 *      @ORM\JoinColumn(name="blog_id", referencedColumnName="id")
 *  },
 *  inverseJoinColumns={
 *      @ORM\JoinColumn(name="tag_id", referencedColumnName="id")
 *  }
 * )
 * @ORM\OrderBy({"name": "ASC"})
 */
private $blogTags;

Это создало таблицу join_table. У меня уже есть таблица join_table. Хотя этот код предназначен для ссылки на кого-то.

Контроллер.php

// This is my old Code
$bp = $em->getRepository('App:BlogPost')->getAllActivePostsByTags($slug, "DESC", $page, self::PAGE_LIMIT);
// This is my New Code
$bp = $em->getRepository('App:BlogTags')->getAllActivePostsByTags($slug, "DESC", $page, self::PAGE_LIMIT);

Репозиторий.php

public function getAllActivePostsByTags($value, $order = "DESC", $currentPage = 1, $limit = 10)
    {
        $query = $this->createQueryBuilder('t')
            ->select('t','p','tx')
            ->innerJoin('t.blogPosts', 'p')
            ->innerJoin('p.blogTags', 'tx')
            ->where('p.isActive = :val1')
            ->andWhere('t.slug = :val2')
            ->setParameter('val1', true)
            ->setParameter('val2', $value)
            ->orderBy('p.id', $order)
            ->getQuery();

        $paginator = $this->paginate($query, $currentPage, $limit);

        return $paginator;
    }

Я не полностью изменил свой старый файл ветки. Так как выдает ошибку во многих местах. Потому что теперь я использую репозиторий тегов вместо блога. Итак, я изменил ветку с помощью

{% include 'frontend/page/blog_home.html.twig' with { 'bp':bp|first.blogPosts } %}

Помогите мне в этом (файл ветки): Существует только один тег, поэтому |первый фильтр ветки Проясните меня с помощью этого фильтра ветки. Правильно ли я поступаю. Дайте мне предложение, чтобы улучшить его. Я пробовал bp[0] Это ошибка.

Наконец: Используя старый код в контроллере, он возвращает 14 дБ обращений. Теперь он возвращает только 8. Даже тегов в посте больше (но старый возвращает больше).

person Sudhakar Krishnan    schedule 27.01.2019