我目前正在使用支持多种语言的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个正确加入查询)。
答案 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",除了:
我知道这不是一个"答案",但希望它可以为您提供一些如何解决问题的好主意。