简体   繁体   English

Symfony2 - Doctrine2:跨数据库连接列抛出映射异常

[英]Symfony2 - Doctrine2: Cross-Database Join Column throws Mapping-Exception

Hi want to make a join between two entities. 嗨想要在两个实体之间建立联接。 The entities are in different databases: 实体位于不同的数据库中:

Here is how I set up my database config: 以下是我设置数据库配置的方法:

doctrine:
    dbal:
    default_connection: default
    connections:
        default:
            driver:   %database_driver%
            host:     %database_host%
            port:     %database_port%
            dbname:   %database_name%
            user:     %database_user%
            password: %database_password%
            charset:  UTF8
            mapping_types:
                enum: string
        data_warehouse:
            driver:   %database_data_warehouse_driver%
            host:     %database_data_warehouse_host%
            port:     %database_data_warehouse_port%
            dbname:   %database_data_warehouse_name%
            user:     %database_data_warehouse_user%
            password: %database_data_warehouse_password%
            charset:  UTF8
            mapping_types:
                enum: string

    orm:
    auto_generate_proxy_classes: %kernel.debug%

    default_entity_manager: default

    entity_managers:
        default:
            connection: default
            mappings:
                MyBundle1: ~


        data_warehouse:
            connection: data_warehouse
            mappings:
                MyBundle2: ~

And these are my entities: 这些是我的实体:

namespace My\Bundle1\Entity;
use My\Bundle1\Entity\MyBundle2Entity;
class MyBundle1Entity
{

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;
}


namespace My\Bundle2\Entity;
class MyBundle2Entity
{

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;


   /**
     * @var MyBundle1Entity
     *
     * @ORM\ManyToOne( targetEntity="My\Bundle1\Entity\MyBundle1Entity")
     * @ORM\JoinColumn(name="my_bundle1_entity_id",  nullable=true)
     */
    private $myBundle1Entity;
}

When I try to use the doctrine:schema:update command, I get an error: 当我尝试使用doctrine:schema:update命令时,出现错误:

php app/console doctrine:schema:create --dump-sql --em=data_warehouse

Error: 错误:

[Doctrine\\Common\\Persistence\\Mapping\\MappingException] [学说\\共同\\持久性\\映射\\ MappingException]
The class 'My\\Bundle1\\Entity\\Bundle1Entity' was not found in the chain configured namespaces My\\Bundle2\\Entity\\Bundle2Entity 在链配置的命名空间My \\ Bundle2 \\ Entity \\ Bundle2Entity中找不到类'My \\ Bundle1 \\ Entity \\ Bundle1Entity'

Is my setup correct or am I doeing something completely wrong? 我的设置是正确的还是我做错了什么? I assume that I define two entity managers and there connections and tell them, what bundles they have to handle. 我假设我定义了两个实体管理器和那里的连接并告诉他们,他们必须处理哪些捆绑包。 I ensure that there are only entities from one database in each bundle. 我确保每个包中只有一个数据库中的实体。

Thanks for your help 谢谢你的帮助

It looks like this question is old, but was never answered. 这个问题看起来很旧,但从未得到过回答。 I'm hoping this answer helps fellow Googlers stumbling across this question. 我希望这个答案可以帮助Google员工绊倒这个问题。

You can't set up a direct relationship between entities across entity managers. 您无法在实体管理器之间建立实体之间的直接关系。 You can set up relationships across bundles, though, if they share the same entity manager. 但是,如果它们共享同一个实体管理器,则可以跨捆绑设置关系。

Relationships between 2 entities using the same entity manager [2.2+]: 使用相同实体管理器[2.2+]的2个实体之间的关系:

Have a look at the Symfony docs on the issue 看看有关该问题Symfony文档

Essentially, in Bundle1, create an interface, then implement it on your entity. 基本上,在Bundle1中,创建一个接口,然后在您的实体上实现它。 In Bundle2, link your @ManyToOne annotation to the interface instead of the entity itself. 在Bundle2中,将@ManyToOne注释链接到接口而不是实体本身。 Then, tell Symfony in the config how to resolve the interface. 然后,在配置中告诉Symfony如何解析接口。

Bundle1: Bundle1:

<?php

// src/My/Bundle1/Entity/Bundle1Entity.php

namespace My\Bundle1\Entity;

use My\Bundle1\Entity\MyBundle2Entity; // <-- NOT NEEDED

interface Bundle1EntityInterface {}

class MyBundle1Entity implements Bundle1EntityInterface
{
    // ...
}

Bundle2: bundle2中:

<?php

// src/My/Bundle2/Entity/Bundle2Entity.php

namespace My\Bundle2\Entity;
class MyBundle2Entity
{
    // ...

    /**
     * @var MyBundle1Entity
     *
     * @ORM\ManyToOne(targetEntity="My\Bundle1\Entity\Bundle1EntityInterface")
     * @ORM\JoinColumn(name="my_bundle1_entity_id", nullable=true)
     */
    private $myBundle1Entity;
}

App Config: App配置:

# app/config/config.yml
doctrine:
    # ....
    orm:
        # ....
        resolve_target_entities:
            My\Bundle1\Entity\Bundle1EntityInterface: My\Bundle1\Entity\Bundle1Entity

Relationships between 2 entities using a different entity manager 使用不同实体管理器的2个实体之间的关系

Because the entities cannot be tied directly, you must hook into the postLoad event to set up the reference, while persisting the id manually. 因为实体不能直接绑定,所以必须挂钩到postLoad事件以设置引用,同时手动持久化id。 See docs for an example and explanation of blending a MongoDB object with an ORM object. 有关将MongoDB对象与ORM对象混合的示例和说明,请参阅docs

Here's a skeleton (getters/setters removed), using 2 entity managers: 这是一个骨架(删除了getters / setters),使用了2个实体管理器:

Entities: 实体:

<?php

// src/My/Bundle1/Entity/Bundle1Entity.php

namespace My\Bundle1\Entity;

class MyBundle1Entity
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;
}


// src/My/Bundle2/Entity/Bundle2Entity.php

namespace My\Bundle2\Entity;
class MyBundle2Entity
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(type="integer")
     */
    private $myBundle1EntityId;

    /**
     * @var MyBundle1Entity
     */
    private $myBundle1Entity;

    public function setMyBundle1Entity($entity)
    {
        $this->myBundle1EntityId = $entity->getId();
        $this->myBundle1Entity = $entity;
    }
}

Event Listener: 事件监听器:

<?php

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\LifecycleEventArgs;

class MyEventSubscriber
{
    public function __construct(EntityManager $bundle1Em)
    {
        $this->bundle1Em = $bundle1Em;
    }

    public function postLoad(LifecycleEventArgs $eventArgs)
    {
        $myBundle2Entity = $eventArgs->getEntity();
        $defaultEm = $eventArgs->getEntityManager();
        $myBundle2EntityReflProp = $defaultEm->getClassMetadata('Entity\MyBundle2Entity')
            ->reflClass->getProperty('myBundle1Entity');
        $myBundle2EntityReflProp->setAccessible(true);
        $myBundle2EntityReflProp->setValue(
            $myBundle1Entity, $this->bundle1Em->getReference('Entity\MyBundle1Entity', $myBundle2Entity->getMyBundle1Id())
        );
    }
}

Obviously, you'd have to register the event listener and pass bundle 1's entity manager as an argument. 显然,您必须注册事件侦听器并将bundle 1的实体管理器作为参数传递。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM