我有以下实体:
<?php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* @ORM\Table(name="zf_categories")
* @ORM\Entity
*/
class Category
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @ORM\Column(name="name", type="string", nullable=false, unique=true)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* @ORM\JoinColumn(name="extend", referencedColumnName="id")
*/
private $extend;
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="extend")
*/
private $children;
/**
* Constructor
*/
public function __construct()
{
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set extend
*
* @param \Application\Entity\Category $extend
* @return Category
*/
public function setExtend(\Application\Entity\Category $extend = null)
{
$this->extend = $extend;
return $this;
}
/**
* Get extend
*
* @return \Application\Entity\Category
*/
public function getExtend()
{
return $this->extend;
}
/**
* Add children
*
* @param \Application\Entity\Category $children
* @return Category
*/
public function addChild(\Application\Entity\Category $children)
{
$this->children[] = $children;
return $this;
}
/**
* Remove children
*
* @param \Application\Entity\Category $children
*/
public function removeChild(\Application\Entity\Category $children)
{
$this->children->removeElement($children);
}
/**
* Get children
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getChildren()
{
return $this->children;
}
}我使用的代码保存数据的格式如下:
----------------------
| id | extend | name |
----------------------
| 1 | NULL | food |
| 2 | 1 | meat |
| 3 | 2 | pork |
----------------------这个实体从“根”到“叶”,所以当我尝试:
$categories = $em->getRepository('Application\Entity\Category')->findOneBy(array('id' => '3'));
foreach($categories->getChildren() as $children)
{
var_dump($children->getId());
}它不工作,这意味着它不显示‘孩子’。
我想从‘叶子’转到‘根’,所以当我有对象#3时,getChildren()应该返回对象#2等等。
如何建立这样的实体有什么建议吗?
var_dump($categories->getChildren())
object(Doctrine\ORM\PersistentCollection)[428]
private 'snapshot' =>
array (size=0)
empty
private 'owner' =>
object(Application\Entity\Category)[415]
private 'id' => int 3
private 'name' => string 'pork' (length=4)
private 'extend' =>
object(DoctrineORMModule\Proxy\__CG__\Application\Entity\Category)[430]
public '__initializer__' =>
object(Closure)[417]
...
public '__cloner__' =>
object(Closure)[418]
...
public '__isInitialized__' => boolean false
private 'id' (Application\Entity\Category) => int 2
private 'name' (Application\Entity\Category) => null
private 'extend' (Application\Entity\Category) => null
private 'children' (Application\Entity\Category) => null
private 'children' =>
&object(Doctrine\ORM\PersistentCollection)[428]
private 'association' =>
array (size=15)
'fieldName' => string 'children' (length=8)
'mappedBy' => string 'extend' (length=6)
'targetEntity' => string 'Application\Entity\Category' (length=27)
'cascade' =>
array (size=0)
empty
'orphanRemoval' => boolean false
'fetch' => int 2
'type' => int 4
'inversedBy' => null
'isOwningSide' => boolean false
'sourceEntity' => string 'Application\Entity\Category' (length=27)
'isCascadeRemove' => boolean false
'isCascadePersist' => boolean false
'isCascadeRefresh' => boolean false
'isCascadeMerge' => boolean false
'isCascadeDetach' => boolean false
private 'em' =>
object(Doctrine\ORM\EntityManager)[342]
private 'config' =>
object(Doctrine\ORM\Configuration)[146]
protected '_attributes' =>
array (size=14)
...
private 'conn' =>
object(Doctrine\DBAL\Connection)[345]
protected '_conn' =>
object(Doctrine\DBAL\Driver\PDOConnection)[400]
...
protected '_config' =>
object(Doctrine\ORM\Configuration)[146]
...
protected '_eventManager' =>
object(Doctrine\Common\EventManager)[346]
...
protected '_expr' =>
object(Doctrine\DBAL\Query\Expression\ExpressionBuilder)[347]
...
private '_isConnected' => boolean true
private '_transactionNestingLevel' => int 0
private '_transactionIsolationLevel' => int 2
private '_nestTransactionsWithSavepoints' => null
private '_params' =>
array (size=8)
...
protected '_platform' =>
object(Doctrine\DBAL\Platforms\MySqlPlatform)[348]
...
protected '_schemaManager' => null
protected '_driver' =>
object(Doctrine\DBAL\Driver\PDOMySql\Driver)[344]
...
private '_isRollbackOnly' => boolean false
protected 'defaultFetchMode' => int 2
private 'metadataFactory' =>
object(Doctrine\ORM\Mapping\ClassMetadataFactory)[343]
private 'em' =>
&object(Doctrine\ORM\EntityManager)[342]
private 'targetPlatform' =>
object(Doctrine\DBAL\Platforms\MySqlPlatform)[348]
...
private 'driver' =>
object(Doctrine\ORM\Mapping\Driver\DriverChain)[150]
...
private 'evm' =>
object(Doctrine\Common\EventManager)[346]
...
protected 'cacheSalt' => string '$CLASSMETADATA' (length=14)
private 'cacheDriver' (Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory) =>
object(Doctrine\Common\Cache\ArrayCache)[149]
...
private 'loadedMetadata' (Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory) =>
array (size=1)
...
protected 'initialized' => boolean true
private 'reflectionService' (Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory) =>
object(Doctrine\Common\Persistence\Mapping\RuntimeReflectionService)[368]
...
private 'unitOfWork' =>
object(Doctrine\ORM\UnitOfWork)[351]
private 'identityMap' =>
array (size=1)
...
private 'entityIdentifiers' =>
array (size=2)
...
private 'originalEntityData' =>
array (size=1)
...
private 'entityChangeSets' =>
array (size=0)
...
private 'entityStates' =>
array (size=2)
...
private 'scheduledForDirtyCheck' =>
array (size=0)
...
private 'entityInsertions' =>
array (size=0)
...
private 'entityUpdates' =>
array (size=0)
...
private 'extraUpdates' =>
array (size=0)
...
private 'entityDeletions' =>
array (size=0)
...
private 'collectionDeletions' =>
array (size=0)
...
private 'collectionUpdates' =>
array (size=0)
...
private 'visitedCollections' =>
array (size=0)
...
private 'em' =>
&object(Doctrine\ORM\EntityManager)[342]
private 'commitOrderCalculator' => null
private 'persisters' =>
array (size=1)
...
private 'collectionPersisters' =>
array (size=0)
...
private 'evm' =>
object(Doctrine\Common\EventManager)[346]
...
private 'listenersInvoker' =>
object(Doctrine\ORM\Event\ListenersInvoker)[352]
...
private 'orphanRemovals' =>
array (size=0)
...
private 'readOnlyObjects' =>
array (size=0)
...
private 'eagerLoadingEntities' =>
array (size=0)
...
private 'eventManager' =>
object(Doctrine\Common\EventManager)[346]
private '_listeners' =>
array (size=1)
...
private 'proxyFactory' =>
object(Doctrine\ORM\Proxy\ProxyFactory)[354]
private 'em' =>
&object(Doctrine\ORM\EntityManager)[342]
private 'uow' =>
object(Doctrine\ORM\UnitOfWork)[351]
...
private 'proxyNs' => string 'DoctrineORMModule\Proxy' (length=23)
private 'metadataFactory' (Doctrine\Common\Proxy\AbstractProxyFactory) =>
object(Doctrine\ORM\Mapping\ClassMetadataFactory)[343]
...
private 'proxyGenerator' (Doctrine\Common\Proxy\AbstractProxyFactory) =>
object(Doctrine\Common\Proxy\ProxyGenerator)[355]
...
private 'autoGenerate' (Doctrine\Common\Proxy\AbstractProxyFactory) => int 1
private 'definitions' (Doctrine\Common\Proxy\AbstractProxyFactory) =>
array (size=1)
...
private 'repositoryFactory' =>
object(Doctrine\ORM\Repository\DefaultRepositoryFactory)[350]
private 'repositoryList' =>
array (size=1)
...
private 'expressionBuilder' => null
private 'closed' => boolean false
private 'filterCollection' =>
object(Doctrine\ORM\Query\FilterCollection)[404]
private 'config' =>
object(Doctrine\ORM\Configuration)[146]
...
private 'em' =>
&object(Doctrine\ORM\EntityManager)[342]
private 'enabledFilters' =>
array (size=0)
...
private 'filterHash' => null
private 'filtersState' => int 1
private 'backRefFieldName' => string 'extend' (length=6)
private 'typeClass' =>
object(Doctrine\ORM\Mapping\ClassMetadata)[369]
public 'name' => string 'Application\Entity\Category' (length=27)
public 'namespace' => string 'Application\Entity' (length=18)
public 'rootEntityName' => string 'Application\Entity\Category' (length=27)
public 'customGeneratorDefinition' => null
public 'customRepositoryClassName' => null
public 'isMappedSuperclass' => boolean false
public 'parentClasses' =>
array (size=0)
empty
public 'subClasses' =>
array (size=0)
empty
public 'namedQueries' =>
array (size=0)
empty
public 'namedNativeQueries' =>
array (size=0)
empty
public 'sqlResultSetMappings' =>
array (size=0)
empty
public 'identifier' =>
array (size=1)
0 => string 'id' (length=2)
public 'inheritanceType' => int 1
public 'generatorType' => int 4
public 'fieldMappings' =>
array (size=2)
'id' =>
array (size=9)
...
'name' =>
array (size=8)
...
public 'fieldNames' =>
array (size=2)
'id' => string 'id' (length=2)
'name' => string 'name' (length=4)
public 'columnNames' =>
array (size=2)
'id' => string 'id' (length=2)
'name' => string 'name' (length=4)
public 'discriminatorValue' => null
public 'discriminatorMap' =>
array (size=0)
empty
public 'discriminatorColumn' => null
public 'table' =>
array (size=2)
'name' => string 'zf_categories' (length=13)
'options' =>
array (size=0)
...
public 'lifecycleCallbacks' =>
array (size=0)
empty
public 'entityListeners' =>
array (size=0)
empty
public 'associationMappings' =>
array (size=2)
'extend' =>
array (size=19)
...
'children' =>
array (size=15)
...
public 'isIdentifierComposite' => boolean false
public 'containsForeignIdentifier' => boolean false
public 'idGenerator' =>
object(Doctrine\ORM\Id\IdentityGenerator)[389]
private 'sequenceName' => null
public 'sequenceGeneratorDefinition' => null
public 'tableGeneratorDefinition' => null
public 'changeTrackingPolicy' => int 1
public 'isVersioned' => null
public 'versionField' => null
public 'reflClass' =>
object(ReflectionClass)[396]
public 'name' => string 'Application\Entity\Category' (length=27)
public 'isReadOnly' => boolean false
protected 'namingStrategy' =>
object(Doctrine\ORM\Mapping\DefaultNamingStrategy)[385]
public 'reflFields' =>
array (size=4)
'id' =>
object(ReflectionProperty)[386]
...
'name' =>
object(ReflectionProperty)[390]
...
'extend' =>
object(ReflectionProperty)[392]
...
'children' =>
object(ReflectionProperty)[409]
...
private '_prototype' (Doctrine\ORM\Mapping\ClassMetadataInfo) =>
object(Application\Entity\Category)[410]
private 'id' => null
private 'name' => null
private 'extend' => null
private 'children' => null
private 'isDirty' => boolean false
private 'initialized' => boolean false
private 'coll' =>
object(Doctrine\Common\Collections\ArrayCollection)[427]
private '_elements' =>
array (size=0)
empty发布于 2014-10-29 08:13:17
因此,问题是:如何实现行为像树的实体?
递归
一种选择是使用递归。实现一个函数,该函数在节点的子节点上循环时创建一个列表。如果一个孩子是叶子,它会在列表中创建一个条目,如果孩子有自己的孩子,它会调用自己(这会创建一个新的列表,等等)。
因为Doctrine 2将延迟加载关联(子),所以当节点树变大时,尤其是当节点的级别越来越高时,这个设置可能会出现问题。最后,您可以执行无数次查询来加载整个树。
嵌套集
嵌套集模型并不是通过存储节点的父节点来形成树的,而是通过存储左右顺序编号和深度来形成树的。这使您能够只使用一个查询就可以获取任意节点的整个树。
DoctrineExtensions库可以帮助您设置和使用遵循嵌套集模型的实体,阅读其树延拓。如果您使用的是Symfony 2,那么需要一捆来集成这个库。如果您使用的是ZendFramework2,您可以阅读如何集成它这里。
选择哪一种
递归对于insert/update操作非常有效,对于读取(select)操作非常低效。
嵌套集对于读取操作是有效的,对于更新操作甚至是有效的,对于插入操作则是低效的。
当您有比读取/更新更多的插入时,请选择递归。但是,当您有更多的读取/更新比插入,所以去嵌套集。
发布于 2014-10-27 23:11:28
下面的代码应该可以帮助您从“叶子”转到“根”。
$category = $em->getRepository('Application\Entity\Category')->find(3);
$this->recursive($category);
...
public function recursive(Category $category)
{
if($category->getExtend()==null){
return;
}
echo $category->getName();
$this->recursive($category->getExtend());
}https://stackoverflow.com/questions/26551878
复制相似问题