处理具有多个关联的doctrine实体的正确方法

时间:2016-05-10 15:16:20

标签: php symfony doctrine-orm

我目前正在使用支持多种语言的Symfony 3构建电子商务网站,并且已经意识到我设计的产品实体需要加入多个其他实体才能使用DQL /查询构建器来加载翻译,产品评论和折扣/特别优惠等内容。但这意味着我将有一个连接块在多个存储库中将是相同的,这看起来是错误的,因为如果我们需要添加或更改连接以加载额外的,则导致必须寻找所有这些块产品数据。

例如在我的CartRepository的loadCart()函数中,我有一个像这样的DQL查询:

SELECT c,i,p,pd,pt,ps FROM 
AppBundle:Cart c 
join c.items i 
join i.product p
left join p.productDiscount pd
join p.productTranslation pt
left join p.productSpecial ps
where c.id = :id

当我在该页面上显示产品列表时,我会在SectionRepository中找到类似的东西,处理这个问题的正确方法是什么?是否有一些地方我可以集中定义为加入的实体(在这种情况下为产品)加载所需的实体列表。我意识到我可以使用延迟加载,但这会导致在页面上运行大量查询(如果我使用的话,显示40个产品需要使用上面的示例运行121个查询而不是1个正确加入查询)。

2 个答案:

答案 0 :(得分:1)

一种方法(这只是我的头脑,有人可能有更好的方法)。你可以很容易地拥有一个集中的querybuilder功能/服务来做到这一点。 querybuilder非常适合以编程方式构建查询。关键区别在于根实体和过滤实体。

E.g。这样的事情。当然注意,这些并不都在同一个地方(它们可能跨越一些服务,存储库等),这只是一个需要考虑的方法的例子。

public function getCartBaseQuery($cartId, $joinAlias = 'o') {

    $qb = $this->getEntityManager()->createQueryBuilder();

    $qb->select($joinAlias)
        ->from('AppBundle:Cart', 'c')
        ->join('c.items', $joinAlias)
        ->where($qb->expr()->eq('c.id', ':cartId'))
        ->setParameter('cartId', $cartId);

    return $qb;
}

public function addProductQueryToItem($qb, $alias) {

    /** @var QueryBuilder $query */
    $qb
        ->addSelect('p, pd, pt, ps')
        ->join($alias.'product', 'p')
        ->leftJoin('p.productDiscount', 'pd')
        ->join('p.productTranslation', 'pt')
        ->join('p.productSpecial', 'ps')
    ;

    return $qb;
}


public function loadCart($cartId) {

    $qbcart = $someServiceOrRepository->getCartBaseQuery($cartId);
    $qbcart = $someServiceOrRepository->addProductQueryToItem($qbcart);

    return $qbcart->getQuery()->getResult();
}

就像我说的,只是一种可能的方法,但希望它能给你一些想法并开始解决问题。

注意:如果你虔诚地为你附加产品数据的实体使用相同的连接别名,你甚至不必在调用中指定它(但我会让它自己配置)。

答案 1 :(得分:1)

您的问题没有一个正确答案。

但是,如果我必须提出建议,我会说看看CQRS(http://martinfowler.com/bliki/CQRS.html),这基本上意味着你有一个独立的阅读模型。

为了使这个尽可能简单,让我们说你建立一个单独的" extended_product"所有数据已加入和反规范化的表。可以使用后台任务定期填充此表,也可以通过每次更新产品或相关实体时触发的命令填充此表。

当您需要读取产品数据时,您将查询此表而不是原始表。当然,没有什么能阻止您使用许多不同的扩展表,并以不同的方式排列数据。

在某种程度上,它的概念非常类似于数据库" views",除了:

  • 它更快,因为您查询实际的表
  • 因为您通过代码创建该表,所以您不仅限于处理数据的单个SQL查询(想想过滤器,聚合等)

我知道这不是一个"答案",但希望它可以为您提供一些如何解决问题的好主意。