原则2:一对多关联缓存



我正在尝试使用Common包中的条令缓存,但我无法让它与一对多、多对一的会话一起工作。我稍后会解释我想做什么。

我的配置:

'configuration' => array(
    'orm_default' => array(
        'metadata_cache'    => 'filesystem',
        'query_cache'       => 'filesystem',
        'result_cache'      => 'filesystem',
        'hydration_cache'   => 'filesystem',
    )
),

我的实体

class Category
{
    /**
     * @ORMId
     * @ORMGeneratedValue
     * @ORMColumn(type="integer")
     *
     * @var string
     */
    protected $id;
    /**
     * @var string
     *
     * @ORMColumn(name="name", type="string", length=100, nullable=false)
     */
    protected  $name;
    /**
     * @var integer
     *
     * @ORMManyToOne(targetEntity="Category", inversedBy="childrenId", fetch="EAGER")
     * @ORMJoinColumn(name="parent_id", referencedColumnName="id")
     */
    protected $parentId;

    /**
     * @ORMOneToMany(targetEntity="Category", mappedBy="parentId", fetch="EAGER")
     */
    protected $childrenId;
}

我的DQL

$result = $this->em->createQueryBuilder()->select('c')
    ->from('AppEntityCategory', 'c')
    ->where('c.parentId IS NULL')
    ->orderBy('c.priority', 'ASC')
    ->getQuery()
    ->setFetchMode("AppEntityCategory", "parentId", DoctrineORMMappingClassMetadata::FETCH_EAGER);
    ->useResultCache(true, 900, 'categories')
    ->getResult();

我有28个类别15其中有parentId
上述查询执行29个SQL查询,但Doctrine仅存储在缓存中1。因此,当我再次运行此查询时,它执行<strong]28个查询>

知道我做错了什么吗?缺少某些缓存配置?缺少DQL中的一些方法?我想缓存所有查询,而不仅仅是一个主查询。

编辑

我想在循环中使用查询结果,如下所示:

foreach($result as $row)
{
    $categories[]['attr'] = $row->getAttribute()->getName();
    $categories[]['value'] = $row->getAttribute()->getValue();
}

但是这种方式缓存不起作用,所以目前我使用的是:

foreach($result as $row)
{
        $attributes = $this->em->createQueryBuilder()->select('c, a.name, a.value')
            ->from('AppEntityCategory', 'c')
            ->innerJoin('AppEntityAttribute', 'a', 'WITH', 'a.id = c.attribute')
            ->where('c.id = :catId')
            ->setParameter('catId', $row['id'])
            ->getQuery()
            ->useResultCache(true, 900, $categoryName.'-attributes')
            ->getArrayResult();
}

但我更愿意处理对象,而不是数组,但我不能,因为如果我使用对象,并且它有关联,那么这个关联将不会被缓存。因此,理想情况下,应该有某种方式来缓存对象+他的所有关联。

关联获取模式

您提供的查询只获取"父"Category实体,这些实体通过子对象的未初始化集合进行水合。访问该集合时(例如,通过迭代这些子集合),Doctrine将加载集合,从而执行另一个查询。它将为第一个查询所水合的所有父类别执行此操作。

将fetch模式设置为EAGER会在完成这些查询时发生更改。Doctrine会在对父类别进行水合后立即执行这些操作,它不会等到您访问集合时才执行(就像提取模式LAZY一样)。但它仍将进行这些查询。

获取联接查询

告诉Doctrine查询类别并将其子类别水合的最简单方法是执行"获取联接"查询:

$queryBuilder = $this->em->createQueryBuilder();
$queryBuilder
    ->select('p', 'c') // [p]arent, [c]hild
    ->from('AppEntityCategory', 'p')
    ->leftJoin('p.children', 'c')
    ->where('p.parent IS NULL')
    ->orderBy('p.priority', 'ASC');
$query = $queryBuilder->getQuery();
$query
    ->useResultCache(true, 900, 'categories')
$result = $query->getResult();

请注意此处的select()leftJoin()调用。

您也不需要更改关联的获取模式(通过调用setFetchMode()),因为查询本身会告诉Doctrine执行您想要的操作。

这样做的结果是,如果Doctrine尚未缓存(或缓存已过时),它将执行1个查询,如果它已缓存(并且仍然是新的),则执行0个查询。

假设

属性$parentId(在Category中)将重命名为$parent。此属性将包含父Category实体或null,但从不包含id。

属性$childrenId将重命名为$children。此属性将包含Category实体的集合(可能为空),但从不包含id的集合(或数组),当然也从不包含单个id。

我上面建议的查询将这些重命名考虑在内。

我完全忽略了这样一个事实,即在您"编辑"之后,一个新的Attribute实体就出现了。这与你的问题或这个答案无关。

更多级别

看起来/听起来你的类别只使用了两个级别(父母和孩子)。当您引入更多级别(孙辈等)时,阅读此模型可能会很快变得非常低效。

当进行3个或更多级别时,您可能需要查看嵌套集模型。它的写操作更重,但读操作高度优化。

DoctrineExtensions库对此提供了支持,还有一个Symfony Bundle。

根据文档:http://doctrine-orm.readthedocs.io/en/latest/reference/dql-doctrine-query-language.html#temporarily-更改dql中的获取模式我认为setFetchMode - EAGER将不适用于您,因为这将产生不会缓存的额外查询。

为什么不用属性加载类别?

$result = $this->em->createQueryBuilder()
    ->select('c, a.name, a.value')
    ->from('AppEntityCategory', 'c')
    ->innerJoin('AppEntityAttribute', 'a', 'WITH', 'a.id = c.attribute')
    ->where('c.parentId IS NULL')
    ->orderBy('c.priority', 'ASC')
    ->getQuery()
    ->useResultCache(true, 900, 'categories')
    ->getResult();

它应该按预期工作。

相关内容

  • 没有找到相关文章

最新更新