具有连接的实体和存储库中的教义可重用标准
Posted
技术标签:
【中文标题】具有连接的实体和存储库中的教义可重用标准【英文标题】:Doctrine reusable Criteria in Entity and Repository with joins 【发布时间】:2017-09-21 11:30:14 【问题描述】:我已经搜索了这个特定问题很长时间,但不确定我在查询中使用 Criteria 是否存在误解,或者它是否不可能(现在?)
这是一个只有最少字段和条件的示例。
我有两个实体:
产品 字段:可见 品牌 字段:活跃在品牌实体中,我有一个方法
"getVisibleProducts()"
我想在哪里获得所有产品
product.visible = 1
在我的 ProductRepository 中,我有一个方法 findAllVisibleForBrand(Brand $brand)
,我想在其中获取所有带有 product.visible = 1
和 brand.active = 1
的产品
因此,我对最佳可重用性的想法是在我的 ProductRepository 中为 product.visible
值制定标准,并将其用于在存储库中进行查询
/**
* @param Brand $brand
*
* @return Product[]
*/
public function findAllVisibleForBrand(Brand $brand)
return $this->createQueryBuilder('product')
->leftJoin('product.brand', 'brand')
->addCriteria(ProductRepository::createVisibleCriteria())
->andWhere('product.brand = :brand')
->setParameter('brand', $brand)
->getQuery()
->execute();
;
/**
* @return Criteria
*/
public static function createVisibleCriteria()
return Criteria::create()
->andWhere(Criteria::expr()->eq('visible', '1'))
;
在我的品牌实体内:
/**
* @return Product[]|ArrayCollection
*/
public function getVisibleProducts()
return $this->getProducts()->matching(ProductRepository::createVisibleCriteria());
这工作正常,没有问题。
BrandRepository 的想法相同
/**
* @return Brand[]
*/
public function findAllActiveBrands()
return $this->createQueryBuilder('brand')
->addCriteria(BrandRepository::createActiveCriteria())
->getQuery()
->execute()
;
/**
* @return Criteria
*/
public static function createActiveCriteria()
return Criteria::create()
->andWhere(Criteria::expr()->eq('active', '1'))
;
现在我的想法是在我的 ProductRepository 中使用品牌活跃标准来仅获取可见的产品,但前提是品牌处于活跃状态。所以我的方法现在看起来像这样:
/**
* @param Brand $brand
*
* @return Product[]
*/
public function findAllVisibleForBrand(Brand $brand)
return $this->createQueryBuilder('product')
->leftJoin('product.brand', 'brand')
->addCriteria(BrandRepository::createActiveCriteria()) // added this line
->addCriteria(ProductRepository::createVisibleCriteria())
->andWhere('product.brand = :brand')
->setParameter('brand', $brand)
->getQuery()
->execute();
;
通过这种方式添加brandActiveCriteria,我得到以下错误:
[Semantical Error] line 0, col 97 near 'active = :active':错误:AppBundle\Entity\Product 类没有名为 active 的字段或关联
正在构建的查询学说如下所示:
SELECT product FROM
AppBundle\Entity\Product product
LEFT JOIN product.brand brand
WHERE
product.active= :active
AND product.visible = :visible
AND product.brand = :brand
将表名添加到标准中适用于存储库中的查询,但不适用于实体中的查询,因为表别名不同。
有没有机会将规则作为标准或在任何其他地方而不在多个类中复制它?
我想到了使用静态函数从 https://knpuniversity.com/screencast/collections/criteria-collection-filtering
【问题讨论】:
【参考方案1】:您可以在条件中添加别名:
public static function createActiveCriteria($alias = null)
return Criteria::create()
->andWhere(Criteria::expr()->eq(($alias ? $alias.'.' : '').'active', '1'))
;
然后你这样称呼你的标准:
// "brand" is the name of the given alias in leftJoin
BrandRepository::createActiveCriteria('brand');
所以您的findAllVisibleForBrand()
方法将如下所示:
public function findAllVisibleForBrand(Brand $brand)
return $this->createQueryBuilder('product')
->leftJoin('product.brand', 'brand')
->addCriteria(BrandRepository::createActiveCriteria('brand')) // Notice the alias parameter here
->addCriteria(ProductRepository::createVisibleCriteria())
->andWhere('product.brand = :brand')
->setParameter('brand', $brand)
->getQuery()
->execute();
;
你的 DQL 应该是这样的:
SELECT product FROM
AppBundle\Entity\Product product
LEFT JOIN product.brand brand
WHERE
brand.active= :active
AND product.visible = :visible
AND product.brand = :brand
【讨论】:
谢谢,这是有效的,唯一的缺点是,我必须在我使用的每个标准中都这样做。我希望我在教义文档中遗漏了一些东西:) 您别无选择,因为 Doctrine 无法知道您在leftJoin
中的别名。在您的示例中,您将其称为“品牌”,但您也可以将其命名为“b”或其他任何名称,因此您必须在条件中明确命名。
所以,我遇到了同样的问题,也在 Doctrine Github 上搜索。这是 Doctrine 的实际错误,他们修复了它。仅供参考:github.com/doctrine/doctrine2/issues/4243以上是关于具有连接的实体和存储库中的教义可重用标准的主要内容,如果未能解决你的问题,请参考以下文章