Symfony2 - Doctrine2:跨数据库连接列抛出映射异常 [英] Symfony2 - Doctrine2: Cross-Database Join Column throws Mapping-Exception

查看:111
本文介绍了Symfony2 - Doctrine2:跨数据库连接列抛出映射异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好想在两个实体之间建立联系。实体位于不同的数据库中:



这是我如何设置我的数据库配置:

  doctrine:
dbal:
default_connection:默认
连接:
默认值:
驱动程序:%database_driver%
主机:%database_host %
port:%database_port%
dbname:%database_name%
用户:%database_user%
密码:%database_password%
charset:UTF8
mapping_types:
枚举:string
data_warehouse:
驱动程序:%database_data_warehouse_driver%
主机:%database_data_warehouse_host%
端口:%database_data_warehouse_port%
dbname:%database_data_warehouse_name%
用户:%database_data_warehouse_user%
密码:%database_data_warehouse_password%
chars et:UTF8
mapping_types:
枚举:string

orm:
auto_generate_proxy_classes:%kernel.debug%

default_entity_manager:默认

entity_managers:
默认值:
连接:默认
映射:
MyBundle1:〜


data_warehouse:
连接:data_warehouse
映射:
MyBundle2:〜

这些是我的实体:

 命名空间My\Bundle1\Entity; 
使用My\Bundle1\Entity\MyBundle2Entity;
class MyBundle1Entity
{

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


命名空间My\Bundle2\Entity;
class MyBundle2Entity
{

/ **
* @var整数
*
* @ 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;
}

当我尝试使用原则:schema:update命令时,我得到一个错误:

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

错误:



[Doctrine\Common\Persistence\\ \\Mapping\MappingException]

在链配置的命名空间中找不到类My\Bundle1\Entity\Bundle1EntityMy\Bundle2\Entity\Bundle2Entity



我的设置是正确的还是我完全错了?我假设我定义了两个实体管理器,并且有连接并告诉他们,他们必须处理哪些bundle。我确保每个包中只有一个数据库中的实体。



感谢您的帮助

解决方案

看起来这个问题很旧,但从未回答过。我希望这个答案有助于Google员工绊倒这个问题。



您不能在实体经理之间建立实体之间的直接关系。您可以在捆绑中设置关系,但是如果他们共享相同的实体管理员。



使用相同实体管理器的2个实体之间的关系[2.2+]:



看看关于问题的Symfony文档



本质上,在Bundle1中,创建一个接口,然后在您的实体上实现。在Bundle2中,将@ManyToOne注释与实体本身链接。然后,告诉Symfony在配置中如何解决界面。



Bundle1:

 <?php 

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

命名空间My\Bundle1\Entity;

使用My\Bundle1\Entity\MyBundle2Entity; //< - NOT NEEDED

interface Bundle1EntityInterface {}

class MyBundle1Entity implements Bundle1EntityInterface
{
// ...

Bundle2:

 <?php 

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

命名空间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 / config.yml 
doctrine:
#....
orm:
#....
resolve_target_entities:
My\Bundle1\Entity\Bundle1EntityInterface:My\Bundle1\Entity\Bundle1Entity

使用不同实体管理器的2个实体之间的关系



由于实体不能直接绑定,钩入postLoad事件以设置引用,同时手动持久化id。请参阅 docs ,将一个MongoDB对象与一个ORM对象进行混合的例子和说明。



这是一个使用2个实体管理器的骨架(getters / setters removed)



实体:

 <?php 

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

命名空间My\Bundle1\Entity;

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


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

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

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

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

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

事件监听器:

 <?php 

使用Doctrine\ORM\EntityManager;
使用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())
) ;
}
}

显然,你必须注册事件监听器并通过捆绑1的实体管理器作为参数。


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:

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

Error:

[Doctrine\Common\Persistence\Mapping\MappingException]
The class 'My\Bundle1\Entity\Bundle1Entity' was not found in the chain configured namespaces My\Bundle2\Entity\Bundle2Entity

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.

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+]:

Have a look at the Symfony docs on the issue

Essentially, in Bundle1, create an interface, then implement it on your entity. In Bundle2, link your @ManyToOne annotation to the interface instead of the entity itself. Then, tell Symfony in the config how to resolve the interface.

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:

<?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/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

Because the entities cannot be tied directly, you must hook into the postLoad event to set up the reference, while persisting the id manually. See docs for an example and explanation of blending a MongoDB object with an ORM object.

Here's a skeleton (getters/setters removed), using 2 entity managers:

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.

这篇关于Symfony2 - Doctrine2:跨数据库连接列抛出映射异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆