我有一個非常簡單的實體(WpmMenu),它保存的菜單項以自引用關係相互連接(調用它的名稱列表)? 所以在我的實體,我有:學說 - 自引用實體 - 禁止兒童讀取
protected $id
protected $parent_id
protected $level
protected $name
所有的getter/setter方法的關係是:
/**
* @ORM\OneToMany(targetEntity="WpmMenu", mappedBy="parent")
*/
protected $children;
/**
* @ORM\ManyToOne(targetEntity="WpmMenu", inversedBy="children", fetch="LAZY")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onUpdate="CASCADE", onDelete="CASCADE")
*/
protected $parent;
public function __construct() {
$this->children = new ArrayCollection();
}
,一切工作正常。當我渲染菜單樹時,我從存儲庫中獲取根元素,獲取子元素,然後遍歷每個子元素,獲取子元素並遞歸執行此操作,直到我呈現每個元素。
發生了什麼(以及我正在尋求解決方案)是這樣的: 目前我有5個等級= 1個物品,每個物品都附有3個等級= 2個物品(並且將來我會使用級別= 3項目)。爲了讓我的菜單樹學說中的所有元素執行:
- 1查詢根元素+
- 1查詢得到5個孩子的根元素(等級= 1)+
- 5查詢每個級別的獲得3個孩子每個電平1項+
- 15查詢(5×3)的(等級= 2),以獲得兒童(等級= 3)2項
總計:22個查詢
所以,我需要找到一個解決方案,理想情況下,我想只有1個查詢。
原來這就是我想要做的事: 在我的實體存儲庫(WpmMenuRepository)我用的QueryBuilder並獲得通過水平排列所有菜單項的平面陣列。獲取根元素(WpmMenu)並從加載的元素數組中手動添加其子元素。然後以遞歸方式對兒童進行此操作。這樣做我可以擁有同一棵樹,但只有一個查詢。
所以這是我:
WpmMenuRepository:
public function setupTree() {
$qb = $this->createQueryBuilder("res");
/** @var Array */
$res = $qb->select("res")->orderBy('res.level', 'DESC')->addOrderBy('res.name','DESC')->getQuery()->getResult();
/** @var WpmMenu */
$treeRoot = array_pop($res);
$treeRoot->setupTreeFromFlatCollection($res);
return($treeRoot);
}
,並在我的WpmMenu實體我有:
function setupTreeFromFlatCollection(Array $flattenedDoctrineCollection){
//ADDING IMMEDIATE CHILDREN
for ($i=count($flattenedDoctrineCollection)-1 ; $i>=0; $i--) {
/** @var WpmMenu */
$docRec = $flattenedDoctrineCollection[$i];
if (($docRec->getLevel()-1) == $this->getLevel()) {
if ($docRec->getParentId() == $this->getId()) {
$docRec->setParent($this);
$this->addChild($docRec);
array_splice($flattenedDoctrineCollection, $i, 1);
}
}
}
//CALLING CHILDREN RECURSIVELY TO ADD REST
foreach ($this->children as &$child) {
if ($child->getLevel() > 0) {
if (count($flattenedDoctrineCollection) > 0) {
$flattenedDoctrineCollection = $child->setupTreeFromFlatCollection($flattenedDoctrineCollection);
} else {
break;
}
}
}
return($flattenedDoctrineCollection);
}
這是發生了什麼:
一切工作正常,但我結束與每個菜單項出現兩次。 ;)而不是22個查詢現在我有23個。所以我實際上惡化了案件。
真的發生了什麼,我認爲,即使我添加了「手動」添加的子項,WpmMenu實體也不會被視爲與數據庫同步,並且只要我對其子項執行foreach循環,在ORM加載中觸發,並添加已經「手動」添加的相同子項。
Q:有沒有辦法阻止/禁止這種行爲,並告訴這些實體他們他們是與數據庫同步所以不需要額外的查詢?
看看這是否有幫助:http://docs.doctrine-project.org/zh/latest/reference/partial-objects.html – gremo
沒有。我沒有部分對象,這似乎是一個壞主意。 – jakabadambalazs