Doctrine orm 原则2:反向自参考实体

Doctrine orm 原则2:反向自参考实体,doctrine-orm,Doctrine Orm,我有以下实体: <?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", precis

我有以下实体:

<?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;
    }
}
此实体从“根”变为“叶”,因此当我尝试时:

$categories = $em->getRepository('Application\Entity\Category')->findOneBy(array('id' => '3'));


foreach($categories->getChildren() as $children)
{
    var_dump($children->getId());
}
它不工作,这意味着它不显示“children”。 我想从“叶”转到“根”,所以当我有对象3时,getChildren应该返回我对象2,依此类推

如何建立这样的实体有什么建议吗

var_dump$categories->getChildren


下面的代码应该可以帮助您从“叶”转到“根”

$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());
}

所以问题是:如何实现一个行为类似于树的实体

递归 一个选择是使用。您实现了一个函数,该函数在节点的子节点上循环时创建一个列表。如果一个子元素是一片叶子,它会在列表中创建一个条目;如果该子元素有自己的子元素,它会称自己为“创建新列表”,等等

由于条令2将延迟加载关联子级,因此当节点树变大时,尤其是当其级别越来越多时,这种设置可能会出现问题。您可以执行无数次查询来加载整个树

嵌套集合 模型不是通过存储节点的父节点来形成树,而是通过存储左/右顺序编号和深度来形成树。这使您能够仅通过一个查询获取任意节点的整个树

该库可以帮助您设置和使用遵循嵌套集模型的图元,请阅读其相关信息。如果您使用的是Symfony 2,那么就没有必要集成此库。如果您使用的是Zend Framework 2,您可以阅读如何集成它

选择哪一个 递归对于插入/更新操作非常有效,对于读选择操作非常低效

嵌套集对于读取操作是有效的,甚至对于更新操作也是有效的,但是对于插入操作是低效的


当插入多于读取/更新时,请使用递归。但是,当您的读取/更新次数多于插入次数时,请选择嵌套集。

您是否复制了确切的代码?如果你的很多注释都被完全破坏了。@SBH不,我没有复制代码。我现在更新了注释,只是跳过了getter和setter,它们是由条令自动生成的。没有添加任何内容。类的构造函数是什么样子的?应该有类似$this->children=newarraycollection的内容;如果你使用var_dump$categories->getChildren;,你会得到什么@SBH我复制了所有setter、getter等的精确代码。我还添加了var_dump response.Root到Leaf:use$node->getChildren。叶到根:使用$node->getExtend。这对我没有帮助,因为我必须找到一种从叶到根的方法。我已经编辑了我的答案,现在它从叶到根。
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
$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());
}