假设我有一个实体Profile
,它与Account
实体有关联。我想使用profileCode = 12345
和获取配置文件,其中相关的Account
的电子邮件地址为my@email.com
。所以,我需要在两个实体上指定一个条件。
为此,我创建了一个自定义存储库Repository\Profile
,现在我想知道如何实现它。我知道我可以使用“原始”DQL查询或使用查询构建器来解决所有这些问题。但是,我觉得它不像我想的那样漂亮,因为它非常接近原始SQL。当然语法有点不同,但从概念上讲,我会在SQL方面考虑比OOP更多。我会做很多这样的事情,所以我真的想以最好的方式去做。
我已经对Criteria
对象进行了一些阅读(文档很稀疏),只要我在单个实体上进行过滤,它看起来真的很棒。在过滤关联实体时,我无法找到使用Criteria
的任何解决方案。
所以基本上我的问题是:有没有什么方法可以使用Criteria
对象直接从数据库和自定义存储库中过滤多个实体?我会真的更愿意在自定义存储库中对其进行编码而不是实体本身,就像我看到一些人那样。这是可能的,还是有任何好的选择,或者是普通的DQL还是查询构建器真的要走的路?
答案 0 :(得分:1)
Criteria只能过滤实体本身的关联,但是如果我理解你的用例,你需要过滤2个级别,所以它不起作用。
你正试图通过“按自己的方式”做事来将学说塑造成不可能的事物。从长远来看,这只会伤害到你。解决方案已经存在,使用DQL非常好,特别是在存储库中。
答案 1 :(得分:0)
我不明白为什么不这样做,但不确定你的协会是如何相关的。 One-to-One
,One-to-Many
或Many-to-Many
如果您尝试从第3个关联深度级别检索记录,例如Account.profile
- > Profile.code
- > Code.xxx (not id)
您需要使用DQL或QueryBuilder来确定Profile和Code加入帐户或解析Code实体以将其提供给Criteria。
假设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();
} 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();
}
}
$account = $em->getRepository('\Entities\Account')->findOneBy(['email' => 'my@email.com']);
$profile = $account->getProfileByCode('12345');