我有一个Account
实体,它具有一个Section
实体的集合。每个Section
实体都有一个Element
实体(OneToMany关联)的集合。我的问题是,取代所有属于某个部分的元素,我想要获取属于和部分的所有元素都与特定帐户相关联。以下是我的数据库模型。过滤与Doctrine2的多对多关联
因此,当我取一个帐户,我希望能够循环通过其相关的部分(这部分是没有问题的),并且对于每个部分,我要通过其元素是环与提取的帐户相关联。现在我有以下代码。
$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;
}
}
问题是它会提取属于给定部分的所有元素,而不管它们与哪个帐户关联。生成的用于获取节的元素的SQL如下所示。
SELECT t0.id AS id1, t0.name AS name2, t0.section_id AS section_id3
FROM mydb.element t0
WHERE t0.section_id = ?
我需要它做的是像下面的东西(可以是任何其他方法)。过滤使用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 = ?
我知道我可以写一个自定义库的方法getElementsBySection($accountId)
或相似,并使用DQL。如果我能做到这一点,并以某种方式覆盖Section
实体上的getElements()
方法,那么这将是完美的。我只是非常希望能通过关联映射或至少通过使用现有的getter方法来实现这一点。理想情况下,当使用帐户对象时,我希望能够像上面的代码片段一样循环,以便在使用对象时抽象“帐户约束”。也就是说,对象的用户无需调用getElementsByAccount()
或Section
对象上的类似对象,因为它看起来不那么直观。
我看着Criteria
对象,但据我记得,它不能用于过滤关联。
那么,完成此操作的最佳方法是什么?如果没有通过使用DQL查询“手动”组装Section
实体和元素,是否有可能?我现在的(和缩短的)源代码可以在下面看到。提前感谢!
/**
* @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
}
第一种解决方案应该可以工作,但似乎不太吸引人,因为如果我理解正确,过滤在内存和SQL中完成。通过存储库方法,我会手动“组装”'Section'对象,对吧?也就是说,自己设置元素,而不是通过关联自动获取元素。也许[这样的事情](http://pastebin.com/CWAadsbB)?在这种情况下,我可能会删除实体上的关联关系,以确保在使用对象之前没有组装对象时不会误取错的部分。好的,顺便说一下! – Andy0708
第一种解决方案是,db将根据定义的关联简单地获取实体。对特定的“Account”进行过滤只会以PHP完成。这就是为什么我建议你使用一个存储库,因为你可以让数据库只提取你实际需要的那些'Element's(所以db做过滤)。 –
我用示例查询更新了我的答案。 –