【问题标题】:doctrine load associated inherited object学说加载关联的继承对象
【发布时间】:2014-04-03 02:02:08
【问题描述】:

问题:如何加载具有关联对象的对象,该对象使用继承映射和原则?

例如使用这些对象: (忽略错别字,我从我的真实示例代码中重命名了东西)

/**
 * @ORM\Table(name="int_entity")
 * @ORM\Entity
 * })
 */
class IntEntity extends BaseEntity
{
    /**
     * @ORM\Column(name="int_value", type="integer", nullable=true)
    **/
    public $intValue;
}

/**
     * @ORM\Table(name="float_entity")
     * @ORM\Entity
     * })
     */
    class floatEntity extends FakeBaseMixedEntity
    {   
        /**
         * @ORM\Column(name="float_value", type="float", nullable=true)
        **/
        public $floatValue;
    }

/** @ORM\MappedSuperclass */
class BaseEntity
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     */
    private $id;

    //could be other variables I guess but I didn't need any. The point of the
    //base class in my case is more of an interface I guess...
}

 /**
     * @ORM\Table(name="Entity_Containing_Inherited_Entity")
     * @ORM\Entity
     * })
     */
    class EntityContainingInheritedEntity
    {
        /**
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="IDENTITY") 
         */
        public $id;

        /**
         * @ORM\Column(name="string_value", type="string")  
         */
        public $stringValue;

        /**
        * @ORM\OneToOne(targetEntity="BaseEntity", cascade={"persist"})
        * @ORM\JoinColumn(name="id", referencedColumnName="id")
        **/
        public $mixedEntity;
    }

加载不工作

$em = $this->getDoctrine()->getManager();
$loadedValue = $em->getRepository('BundleName:EntityContainingInheritedEntity')->findAll();

不过保存

public function indexAction(Request $request)
{
    $floatE = new floatEntity();
    $floatE->floatValue = 1.01;
    $floatE->setId(rand());

    $floatEContainer = new EntityContainingInheritedEntity();
    $floatEContainer->stringValue = 'hello';
    $floatEContainer->mixedEntity = $floatE;

    $intE = new intEntity();
    $intE->intValue = 100;
    $intE->setId(rand());

    $intEContainer = new EntityContainingInheritedEntity();
    $intEContainer->stringValue = 'hello';
    $intEContainer->mixedEntity = $intE;

    $em = $this->getDoctrine()->getManager();
    $em->persist($floatEContainer);
    $em->persist($intEContainer );
    $em->flush();
}

加载时说代理不存在。因此,我进行了搜索,首先,当存在这样的继承映射时,学说甚至不应该尝试制作代理(至少我是这样解释文档http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html#performance-impact

我已经清除了我的缓存,没有任何改变。
我已尝试将即时加载添加到注释中,但没有任何改变。
我也从我的搜索中得到了要点我应该使用 DQL 而不是 findAll() 下面有相同的代理缓存错误消息

$query = $em->createQuery("SELECT u FROM Path\To\Entity\EntityContainingInheritedEntity u");
$users = $query->getResult();

提到的错误消息:ContextErrorException:警告:需要(/path/app/cache/dev/doctrine/orm/Proxies/__CG__BundleNameEntityBaseEntity.php):无法打开流:/path/vendor/doctrine 中没有这样的文件或目录/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php

顺便说一句,这并不能解决我的问题:Doctrine 2 Inheritance Mapping with Association

【问题讨论】:

  • 你使用的是真正的继承吗?因为在示例中我只看到使用了@MappedSuperClass,这与表继承不同。
  • 这就是发生的事情。我有一个 type1 和 type2 以及一个底座。我想在表单和保存到数据库中都使用它。保存到数据库不起作用,所以我更改了委派,所以我有 type1 包含 commontype 和 type2 包含 commontype。但是,这弄乱了表格,所以我将其切换为 commontype 包含 type1 或 type 2。这适用于保存/表格!但是当我尝试从数据库加载时它没有。所以如果我做了表继承,我还不如回到开头,从而有一个无限循环的不工作的东西。所以现在回答你的问题不。
  • @AlbertoFernández 在我的脑海中映射的超类仍然被认为是继承。我应该更改问题的名称吗?
  • 当然,它们是class继承,但没有database继承,这是Doctrine非常强大的特性。至于你的问题本身,我不太明白你的问题是什么,我看到你在做一些奇怪的事情(比如在通常内部处理时调用setId(rand()))。
  • 那只是我懒惰。我也没有兰特。我的问题是当我尝试从数据库加载时,它无法使用存储库工作。现在这无关紧要,只是表单如何从数据库中加载实体。

标签: symfony doctrine-orm


【解决方案1】:

根据 Alberto Fernandez 的评论,我只是不应该做我所做的事情。这让我很困惑,因为它保存正确。尽管如此,在他没有任何关于如何正确做事的例子的情况下,我继续搜索。我发现解决我的问题的最佳方法是不映射关联实体。相反,我迷上了事件监听器,即 http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.htmlhttp://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html 这让我能够完全按照我想要的方式持久化和加载关联实体。我将在我的解决方案中再次使用上面的示例。

EntityContainingInheritedEntity 更改为

/**
* @ORM\Table(name="Entity_Containing_Inherited_Entity")
* @ORM\Entity
* })
*/
class EntityContainingInheritedEntity
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY") 
     */
    public $id;

    /**
     * @ORM\Column(name="string_value", type="string")  
     */
    public $stringValue;

    public $mixedEntity;

    public $mixedEntityType;

    public function load($em)
    {
        $this->mixedEntity= $em->getRepository("BundleName:{$this->mixedEntityType}")->find($this->id);
    }

    public function save($em)
    {
        $this->mixedEntity->SetId($this->id);
        $em->persist($this->mixedEntity);
        $em->flush();
    }

    public function delete($em)
    {       
        $em->remove($this->mixedEntity);
        $em->flush();
    }

}

我将此添加到我的 config.yml

services:
    my.listener:
        class: Path\To\EventListeners\RecordAssociationManager
        tags:
            - { name: doctrine.event_listener, event: postPersist }
    my.listener2:
        class: Path\To\EventListeners\RecordAssociationManager
        tags:
            - { name: doctrine.event_listener, event: preRemove }
    my.listener3:
        class: Path\To\EventListeners\RecordAssociationManager
        tags:
            - { name: doctrine.event_listener, event: postLoad }

然后制作事件监听类

namespace Path\To\EventListeners;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Path\To\Entity\EntityContainingInheritedEntity;

class RecordAssociationManager
{
    public function preRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        if ($entity instanceof EntityContainingInheritedEntity) 
        {
            $entity->delete($entityManager);
        }
    }
    public function postPersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        if ($entity instanceof EntityContainingInheritedEntity) 
        {
            $entity->save($entityManager);
        }
    }
    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        if ($entity instanceof EntityContainingInheritedEntity) 
        {
            $entity->load($entityManager);
        }
    }
}

【讨论】:

  • 我几乎不想接受我的答案,因为它感觉有点 hacky 虽然在文档中它甚至建议非映射关联实体持久性作为挂钩这些事件的用途所以我猜它是't。
猜你喜欢
  • 2013-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多