Symfony4.1原则ManyToMany减少查询数量

时间:2018-11-20 06:16:25

标签: mysql orm doctrine many-to-many symfony4

我正在做一个项目。实体是Blog,Category,Tags。博客和标签处于 ManyToMany 关系中。我的存储库查询是通过“标签”过滤器来提取数据的。

CODE1:

/**
 * @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;
}

此代码可以正常工作。所有标签(帖子中的标签数)均正确显示。但是,数据库查询号为14 。然后,当我取消注释选择时,

CODE2:

/**
 * @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)还是我需要做些微调整以减少数据库命中数。请指导我。

2 个答案:

答案 0 :(得分:1)

这是两种情况下的预期行为。

案例1)您只需选择BlogPost实体。因此,您告诉该学说要获取所有具有Slug = value的BlogTag的BlogPost。 生成的SQL查询仅返回blog_post表中的列值,因此仅合并返回的BlogPost实体,而不会合并每个BlogPost内部的BlogTag集合。

当您尝试访问BlogPost的标签时,会生成新查询以获取并补充其收藏集。

这就是在这种情况下您获得更多查询的原因。

案例2),您还选择了已过滤的BlogTag实体,并且将仅将此已过滤的BlogTag灌水(放入)到每个BlogPost的集合中。

当您尝试访问BlogPost的BlogTag时,您将获得符合条件的已过滤查询,该查询符合querybuilder中的条件。

要强制准则从数据库中“重新加载”数据,您应该刷新 blogPost实体:

 $em->refresh($blogPost);

,并且还在关系定义的cascade operations上包含 refrech 选项:

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

参考文献:

答案 1 :(得分:0)

感谢@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。尽管此代码仅供参考。

Controller.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);

Repository.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。即使帖子中有更多标签(但旧标签会返回更多标签)。