我有一個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做過濾)。 –
我用示例查詢更新了我的答案。 –