tl;dr getManagerForClass()
方法如何找出哪个实体管理器适合特定类?
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.
在我的控制器中,我尝试使用 Doctrine 的 getManagerForClass() 方法来查找每个类使用哪个管理器,如 在此博客上 和 这个答案.
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);
这是我的 Doctrine 配置:
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: EntityPostgres
oracle:
connection: oracle
mappings:
AppBundle:
type: annotation
dir: EntityOracle
我的文件夹结构如下:
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");
...我得到了 Postgres 的实体管理器.
...I get the entity manager for Postgres.
但是如果我只是简单地切换实体管理器配置,将一个用于 oracle 的配置放在首位,则之前的调用有效,但以下无效:
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");
getManagerForClass()
循环遍历每个管理器,并检查每个管理器的类是否非瞬态":
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;
}
}
这一直到 AnnotationDriver->isTransient()
.此处文档说明如下:
This goes all the way down to AnnotationDriver->isTransient()
. Here the doc says the following:
如果一个类使用 AnnotationDriver::entityAnnotationClasses 中的注解进行注解,则该类是非瞬态的.
A class is non-transient if it is annotated with an annotation from the AnnotationDriver::entityAnnotationClasses.
@Entity
似乎是使类非瞬态的注释之一.但是,我的任何实体怎么可能是短暂的?驱动程序如何仅根据注释区分属于特定管理器的实体?我一定是错过了更高级别的课程.
@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.
该方法在使用 yml
映射时有效.
The method works when using yml
mappings.
我有点预料到这种行为.不同之处在于不同驱动程序中 isTransient() 方法的实现.如果元数据文件存在于映射配置的 dir:
目录中,isTransient 的 FileDriver 实现将返回 true
.
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.
我希望 AnnotationDriver 仅在指定的 dir:
目录中包含的实体中搜索注释,但它似乎忽略了该参数.还是我应该使用另一个?
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?
好不容易解决了.解决方案是使用 prefix
参数.
At long last, I solved it.
The solution was using the prefix
parameter.
entity_managers:
postgres:
connection: postgres
mappings:
AppBundle:
type: annotation
dir: EntityPostgres
prefix: AppBundleEntityPostgres
alias: Postgres
oracle:
connection: oracle
mappings:
AppBundle:
type: annotation
dir: EntityOracle
prefix: AppBundleEntityOracle
alias: Oracle
prefix
参数被传递给相应的实体管理器服务,并被添加到 entityNamespaces
属性,否则默认为 AppBundle/Entity
.然后,注释驱动程序将检查在该特定命名空间中的注释,而文件驱动程序检查通过 dir
参数指定的目录中的现有映射文件.(alias
参数不是强制性的.)
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() 没有返回正确的实体管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!