与原则2中的标准对象相关联的过滤


Filtering on association with criteria object in Doctrine 2

假设我有一个与Account实体有关联的实体Profile。我想获取profileCode = 12345 的配置文件,其中相关的Account具有my@email.com的电子邮件地址。因此,我需要在两个实体上指定一个条件。

为此,我创建了一个自定义存储库Repository'Profile,现在我想知道如何实现这一点。我知道我可以使用"原始"DQL查询或使用查询生成器来解决所有这些问题。然而,我觉得它不像我想的那么漂亮,因为它非常接近原始SQL。当然语法有点不同,但从概念上讲,我更倾向于考虑SQL而不是OOP。我会经常做这些事情,所以我真的在努力用最好的方式来做。

我对Criteria对象做了一些阅读(文档很少),只要我对单个实体进行过滤,它看起来真的很棒。在过滤关联实体时,我无法找到使用Criteria的任何解决方案。

所以基本上我的问题是:是否有任何方法可以使用Criteria对象直接从数据库中过滤多个实体,并在自定义存储库中?我真的更喜欢在自定义存储库中编码,而不是像我看到的一些人那样在实体本身中编码。这是可能的吗?或者有什么好的替代方案吗?或者纯DQL或查询构建器真的是可行的吗?

标准只能过滤实体本身的关联,但如果我理解你的用例,你需要过滤2层深度,所以它不会工作。

你想要按照"你的方式"做事,试图把教义塑造成不符合教义的东西。从长远来看,这只会伤害到你。解决方案已经有了,使用DQL是非常好的,特别是在存储库中。

我不明白为什么不,虽然不确定你的关联是如何相关的。One-to-OneOne-to-ManyMany-to-Many

如果你试图从第3关联深度级别检索记录,如Account.profile ->Profile.codeCode.xxx (not id)您将需要使用DQL或QueryBuilder来建立什么概要文件和代码加入帐户或解析代码实体提供给标准。

假设One-to-Many,其中一个帐户有多个配置文件。您也可以选择在实体本身中定义它,以使其更容易管理并减少对getProfiles()的额外调用。

存储库使用

use Doctrine'ORM'EntityRepository;
use Doctrine'Common'Collections'Criteria;
class AccountRepository extends EntityRepository {
   
    /**
     * @var string|Account $accountOrEmail
     * @var string $code
     * @return Profile|null
     */
    public function getAccountProfileByEmailAndCode($accountOrEmail, $code)
    {
         try{
             $account = ($accountOrEmail instanceof Account ? $accountOrEmail: $this->findOneBy(['email' => $accountOrEmail]));
             if (!$account instanceof Account) {
                 throw new 'InvalidArgumentException('Unknown Account Specified.');
             }
             $criteria = Criteria::create()->setMaxResult(1);
             $expr = $criteria::expr();
             $criteria->where($expr->eq('code', $code));
             return $account->getProfiles()->matching($criteria)->first() ?: null;
         } catch('Exception $e) {
             return null;
         }
    }
}
$accountRepo = $em->getRepository(''Entities'Account');
$profile = $accountRepo->getAccountProfileByEmailAndCode('my@email.com', '12345');

实体使用

use Doctrine'Common'Collections'Criteria;
/**
 * @ORM'Entity(repositoryClass="AccountRepository")
 */
class Account {
    // ...
    
    public function getProfiles(Criteria $criteria = null)
    {
        if ($criteria instanceof Criteria) {
            return $this->profiles->matching($criteria);
        }
        return $this->profiles;
    }
    /**
     * @var string $code
     * @return null|Profile
     */
    public function getProfileByCode($code)
    {
         $criteria = Criteria::create()->setMaxResult(1);
         $expr = $criteria::expr();
         $criteria->where($expr->eq('code', $code));
         return $this->getProfiles($criteria)->first() ?: null;
    }
}
$account = $em->getRepository(''Entities'Account')->findOneBy(['email' => 'my@email.com']);
$profile = $account->getProfileByCode('12345');