And*_*708 5 php orm doctrine-orm
我有一个拥有Account实体集合的Section实体.每个Section实体都有一个实体集合Element(OneToMany关联).我的问题是,我想获取属于某个部分并与特定帐户相关联的所有元素,而不是获取属于某个部分的所有元素.下面是我的数据库模型.

因此,当我获取一个帐户时,我希望能够遍历其关联的部分(这部分没有问题),并且对于每个部分,我想循环遍历与获取的帐户关联的元素.现在我有以下代码.
$repository = $this->objectManager->getRepository('MyModule\Entity\Account');
$account = $repository->find(1);
foreach ($account->getSections() as $section) {
foreach ($section->getElements() as $element) {
echo $element->getName() . PHP_EOL;
}
}
Run Code Online (Sandbox Code Playgroud)
问题是它获取属于给定部分的所有元素,无论它们与哪个帐户相关联.生成的用于获取节的元素的SQL如下所示.
SELECT t0.id AS id1, t0.name AS name2, t0.section_id AS section_id3
FROM mydb.element t0
WHERE t0.section_id = ?
Run Code Online (Sandbox Code Playgroud)
我需要它做的事情如下(可能是任何其他方法).使用SQL完成过滤非常重要.
SELECT e.id, e.name, e.section_id
FROM element AS e
INNER JOIN account_element AS ae ON (ae.element_id = e.id)
WHERE ae.account_id = ?
AND e.section_id = ?
Run Code Online (Sandbox Code Playgroud)
我知道我可以getElementsBySection($accountId)在自定义存储库中编写方法或类似方法并使用DQL.如果我可以这样做并以某种方式覆盖实体getElements()上的方法Section,那么这将是完美的.我非常希望是否有办法通过关联映射或至少通过使用现有的getter方法来实现这一点.理想情况下,当使用帐户对象时,我希望能够像上面的代码片段一样循环,以便在使用对象时抽象出"帐户约束".也就是说,对象的用户不需要在对象上调用getElementsByAccount()或类似Section,因为它看起来不太直观.
我查看了Criteria对象,但据我记忆,它不能用于过滤关联.
那么,实现这一目标的最佳方法是什么?是否可以Section通过使用DQL查询"手动"组合实体元素?我目前(和缩短)的源代码如下所示.非常感谢提前!
/**
* @ORM\Entity
*/
class Account
{
/**
* @var int
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
protected $id;
/**
* @var string
* @ORM\Column(type="string", length=50, nullable=false)
*/
protected $name;
/**
* @var ArrayCollection
* @ORM\ManyToMany(targetEntity="MyModule\Entity\Section")
* @ORM\JoinTable(name="account_section",
* joinColumns={@ORM\JoinColumn(name="account_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="section_id", referencedColumnName="id")}
* )
*/
protected $sections;
public function __construct()
{
$this->sections = new ArrayCollection();
}
// Getters and setters
}
/**
* @ORM\Entity
*/
class Section
{
/**
* @var int
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
protected $id;
/**
* @var string
* @ORM\Column(type="string", length=50, nullable=false)
*/
protected $name;
/**
* @var ArrayCollection
* @ORM\OneToMany(targetEntity="MyModule\Entity\Element", mappedBy="section")
*/
protected $elements;
public function __construct()
{
$this->elements = new ArrayCollection();
}
// Getters and setters
}
/**
* @ORM\Entity
*/
class Element
{
/**
* @var int
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
protected $id;
/**
* @var string
* @ORM\Column(type="string", length=50, nullable=false)
*/
protected $name;
/**
* @var Section
* @ORM\ManyToOne(targetEntity="MyModule\Entity\Section", inversedBy="elements")
* @ORM\JoinColumn(name="section_id", referencedColumnName="id")
*/
protected $section;
/**
* @var \MyModule\Entity\Account
* @ORM\ManyToMany(targetEntity="MyModule\Entity\Account")
* @ORM\JoinTable(name="account_element",
* joinColumns={@ORM\JoinColumn(name="element_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="account_id", referencedColumnName="id")}
* )
*/
protected $account;
// Getters and setters
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,您希望能够检索an 的所有Elements 的所有s ,但前提是这些s 与 that 关联,并且来自 Account 中的 getter。SectionAccountElementAccount
首先:实体永远不应该知道存储库。这打破了帮助您更换持久层的设计原则。这就是为什么您不能从实体内部简单地访问存储库的原因。
仅吸气剂
如果您只想在实体中使用 getter,可以通过添加以下 2 个方法来解决此问题:
class Section
{
/**
* @param Account $accout
* @return Element[]
*/
public function getElementsByAccount(Account $accout)
{
$elements = array();
foreach ($this->getElements() as $element) {
if ($element->getAccount() === $account) {
$elements[] = $element->getAccount();
}
}
return $elements;
}
}
class Account
{
/**
* @return Element[]
*/
public function getMyElements()
{
$elements = array()
foreach ($this->getSections() as $section) {
foreach ($section->getElementsByAccount($this) as $element) {
$elements[] = $element;
}
}
return $elements;
}
}
Run Code Online (Sandbox Code Playgroud)
存储库
上面的解决方案可能会执行多个查询,具体数量取决于有多少Sections 和Elements 与Account.
当您使用存储库方法时,您可能会获得性能提升,因此您可以优化用于检索所需内容的一个或多个查询。
一个例子:
class ElementRepository extends EntityRepository
{
/**
* @param Account $account [description]
* @return Element[]
*/
public function findElementsByAccount(Account $account)
{
$dql = <<< 'EOQ'
SELECT e FROM Element e
JOIN e.section s
JOIN s.accounts a
WHERE e.account = ?1 AND a.id = ?2
EOQ;
$q = $this->getEntityManager()->createQuery($dql);
$q->setParameters(array(
1 => $account->getId(),
2 => $account->getId()
));
return $q->getResult();
}
}
Run Code Online (Sandbox Code Playgroud)
PS:要使此查询正常工作,您需要将Section和之间的多对多关联定义Account为双向关联。
代理方法
混合解决方案是添加一个代理方法Account,将调用转发到您传递给它的存储库。
class Account
{
/**
* @param ElementRepository $repository
* @return Element[]
*/
public function getMyElements(ElementRepository $repository)
{
return $repository->findElementsByAccount($this);
}
}
Run Code Online (Sandbox Code Playgroud)
这样,实体仍然不知道存储库,但您允许将存储库传递给它。
实现此方法时,不要使用ElementRepository扩展EntityRepository,而是在创建时注入EntityRepository。这样您仍然可以交换持久层而不改变您的实体。
| 归档时间: |
|
| 查看次数: |
2389 次 |
| 最近记录: |