Symfony 2.8:Doctrine getManagerForClass()没有返回正确的实体管理器 [英] Symfony 2.8 : Doctrine getManagerForClass() not returning the right Entity Manager

查看:160
本文介绍了Symfony 2.8:Doctrine getManagerForClass()没有返回正确的实体管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

tl; dr getManagerForClass()方法如何找出哪个实体管理器是特定类的正确的?



我已经制定了一个通用控制器,它应该能够处理不同实体的基本操作。
我也连接到两个不同的数据库,所以我使用两个实体管理器。



在我的控制器中,我试图使用Doctrine的getManagerForClass )方法来查找每个类使用哪个经理,如这个博客这个SO答案



但是,该方法似乎并没有区分我的两个实体管理器,只需返回配置中的第一个。



我的控制器动作开始如下:

  public function indexAction($ namespace,$ entityName)
{
$ classFullName =AppBundle:$ namespace\\ $ entityName;
$ em = $ this-> getDoctrine() - > getManagerForClass($ classFullName);

这是我的Doctrine配置:

  dbal:
default_connection:postgres
连接:
postgres:
驱动程序:pdo_pgsql
主机:%database_host%
port:%database_port%
dbname:%database_name%
user:%database_user%
password:%database_password%
charset:UTF8

oracle:
驱动程序:oci8
主机:%oracle_host%
端口:%oracle_port%
dbname:%oracle_name%
用户:%oracle_user%
密码:%oracle_password%
charset:UTF8

orm:
auto_generate_proxy_classes:true
entity_managers :
postgres:
连接:postgres
映射:
AppBundle:
类型:注释
dir:Entity\Postgres
oracle:
连接:oracle
映射:
AppBundle:
类型:注释
dir:Entity\Oracle

我的文件夹结构如下:

  AppBundle 
| ___控制器
| | ___ EntityController.php
|
| ___实体
| ___ Postgres
| | ___ SomePostgresBasedEntity.php
|
| ___ Oracle
| ___ SomeOracleBasedEntity.php

现在我不知道该方法如何工作,以及如果不通过配置,它应该如何知道映射。
但是,如果我这样称呼,例如:

  $ em = $ this-> getDoctrine() - > getManagerForClass( 的appbundle:Oracle\\SomeOracleBasedEntity); 

...我收到Postgres的实体经理。



但是,如果我简单地切换实体管理器配置,首先将其用于oracle,则以前的调用将起作用,但以下操作不会:

  $ em = $ this-> getDoctrine() - > getManagerForClass(AppBundle:Postgres\\\SomePostgresBasedEntity); 



更新1



getManagerForClass()循环遍历每个经理和每个经理,检查该类是否是非暂态:

  foreach($ this-> manager as $ id){
$ manager = $ this-> getService($ id);

if(!$ manager-> getMetadataFactory() - > isTransient($ class)){
return $ manager;
}
}

这一直到 AnnotationDriver-> isTransient()。这里的doc表示如下:


如果使用AnnotationDriver :: entityAnnotationClasses的注释对类进行注释,则该类是非暂态的。 / p>

@Entity 似乎是这些注释之一,短暂的。
但是,那么,我的实体怎么可能是暂时的?驾驶员如何根据其注释区分属于特定经理的实体?
我一定错过了更高级别的课程。



更新2



当使用 yml 映射。



我有一种期待这种行为。不同之处在于不同驱动程序中isTransient()方法的实现。如果元数据文件存在于映射配置的 dir:目录中,则isTransient的FileDriver实现将返回 true p>

我会期望AnnotationDriver仅在包含在指定的 dir:目录中的实体中搜索注释,但它似乎忽略了这个参数。
还是应该使用另一个?

解决方案

最后,我解决了。
解决方案是使用前缀参数。

  entity_managers :
postgres:
连接:postgres
映射:
AppBundle:
类型:注释
dir:Entity\Postgres
前缀:AppBundle \Entity\Postgres
别名:Postgres
oracle:
连接:oracle
映射:
AppBundle:
类型:注释
dir :Entity\Oracle
前缀:AppBundle\Entity\Oracle
别名:Oracle



说明



前缀参数传递给相应的实体管理器服务,并添加到 entityNamespaces 属性,默认为 AppBundle / Entity
注释驱动程序然后将检查该特定命名空间中的注释,而文件驱动程序会检查通过 dir 参数。
别名参数不是必需的。)



至少这就是我的理解。


tl;dr How does the getManagerForClass() method find out which entity manager is the right one for a specific class?

I've made a generic controller that should be able to handle basic actions for different entities. I also have connections to two different databases, so I'm using two entity managers.

In my controller, I'm trying to use Doctrine's getManagerForClass() method to find which manager to use for each class, as explained on this blog and this SO answer.

But the method does not seem to differentiate my two entity managers and simply returns the first one in the configuration.

My controller action starts like this:

public function indexAction($namespace, $entityName)
{
    $classFullName = "AppBundle:$namespace\\$entityName";
    $em = $this->getDoctrine()->getManagerForClass($classFullName);

This is my Doctrine configuration:

dbal:
    default_connection: postgres
    connections:
        postgres:
            driver:   pdo_pgsql
            host:     "%database_host%"
            port:     "%database_port%"
            dbname:   "%database_name%"
            user:     "%database_user%"
            password: "%database_password%"
            charset:  UTF8

        oracle:
            driver:   oci8
            host:     "%oracle_host%"
            port:     "%oracle_port%"
            dbname:   "%oracle_name%"
            user:     "%oracle_user%"
            password: "%oracle_password%"
            charset:  UTF8

orm:
    auto_generate_proxy_classes: true
    entity_managers:
        postgres:
            connection: postgres
            mappings:
                AppBundle:
                   type:      annotation
                   dir:       Entity\Postgres
        oracle:
            connection: oracle
            mappings:
                AppBundle:
                  type:       annotation
                  dir:        Entity\Oracle

And my folder structure is as follows:

AppBundle
    |___Controller
    |      |___EntityController.php
    |
    |___Entity
           |___Postgres
           |     |___SomePostgresBasedEntity.php
           |
           |___Oracle
                 |___SomeOracleBasedEntity.php

Now I don't know exactly how the method works, and how it it supposed to know about the mapping if not through the configuration. But if I call it this way, for example:

 $em = $this->getDoctrine()->getManagerForClass("AppBundle:Oracle\\SomeOracleBasedEntity");

...I get the entity manager for Postgres.

But if I simply switch the entity manager configuration, putting the one for oracle first, the previous call works, but the following doesn't:

 $em = $this->getDoctrine()->getManagerForClass("AppBundle:Postgres\\SomePostgresBasedEntity");

Update 1

getManagerForClass() cycles through every manager and for each one, checks if the class is "non-transient":

    foreach ($this->managers as $id) {
        $manager = $this->getService($id);

        if (!$manager->getMetadataFactory()->isTransient($class)) {
            return $manager;
        }
    }

This goes all the way down to AnnotationDriver->isTransient(). Here the doc says the following:

A class is non-transient if it is annotated with an annotation from the AnnotationDriver::entityAnnotationClasses.

@Entity seems to be one of those annotations that makes a class non-transient. But then, how could any of my entities be transient at all? How could the driver distinguish an entity that belongs to a specific manager based solely on its annotations? I must have missed something in the higher level classes.

Update 2

The method works when using yml mappings.

I kind of expected this behaviour. The difference comes from the implementations of the isTransient() method in the different drivers. The FileDriver implementation of isTransient returns true if the metadata file exists in the dir: directory of the mapping configuration.

I would have expected the AnnotationDriver to search for annotations only in the entities contained in the specified dir: directory, but it seems to ignore that parameter. Or should I use another one?

解决方案

At long last, I solved it. The solution was using the prefix parameter.

entity_managers:
    postgres:
        connection: postgres
        mappings:
            AppBundle:
                type: annotation
                dir: Entity\Postgres
                prefix: AppBundle\Entity\Postgres
                alias: Postgres
    oracle:
        connection: oracle
        mappings:
            AppBundle:
                type: annotation
                dir: Entity\Oracle
                prefix: AppBundle\Entity\Oracle
                alias: Oracle

Explanation

The prefix parameter gets passed to the corresponding Entity Manager service, and is added to the entityNamespaces property, which otherwise defaults to AppBundle/Entity. The Annotation Driver will then check for annotations in that specific namespace, whereas the File Driver checks for existing mapping files in the directory specified through the dir parameter. (The alias parameter is not mandatory.)

At least, that's how I understand it.

这篇关于Symfony 2.8:Doctrine getManagerForClass()没有返回正确的实体管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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