使用错误连接的 Doctrine 实体管理器

Doctrine entity manager using wrong connection

根据 Symfony docs,可以配置多个实体管理器,方法是在 config/packages/doctrine.yaml 中列出它们,然后在控制器中选择一个特定的实体管理器,如下所示:$this->getDoctrine()->getManager('customer');.

我设置了我的 config/packages/doctrine.yaml:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                # configure these for your database server
                url: '%env(DATABASE_URL)%'
                driver: 'pdo_mysql'
                server_version: '8.0'
                charset: utf8mb4
            meter:
                # configure these for your database server
                url: '%env(DATABASE_METER_URL)%'
                driver: 'pdo_mysql'
                server_version: '8.0'
                charset: utf8mb4

    orm:
        default_entity_manager: default
        entity_managers:
            default:
                connection: default
                naming_strategy: doctrine.orm.naming_strategy.underscore
                mappings:
                    App:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/Entity'
                        prefix: 'App\Entity'
                        alias: App
            meter:
                connection: meter
                naming_strategy: doctrine.orm.naming_strategy.underscore
                mappings:
                    App:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/Entity'
                        prefix: 'App\Entity'
                        alias: App

然后尝试使用

进行查询
$meterEntityManager = $this->getDoctrine()->getManager('meter');
$meter = $meterEntityManager->getRepository(Entity\Meter::class)->find($meterId);

但是,$meterEntityManager->getRepository(Entity\Meter::class)->find($meterId) 的结果是来自名为 default 的数据库连接的一行,而不是名为 meter 的行——就好像代码是

$entityManager = $this->getDoctrine()->getManager('default');
$meter = $entityManager->getRepository(Entity\Meter::class)->find($meterId);

当我检查与 $meterEntityManager->getConnection()->getParams() 的连接时,它正确地列出了 meter 连接而不是 default 连接的参数,因此我可以从 meter 通过直接在连接对象上执行查询来连接数据库:

$meterEntityManager = $this->getDoctrine()->getManager('meter');
$stmt = $meterEntityManager->getConnection()->prepare('SELECT * FROM meter WHERE id = :id');
$stmt->execute(['id' => $meterId]);
$meter = $stmt->fetch();

但最终我想通过 getRepository(Entity\Meter::class) 提供的方法获取行,因此返回的数据会自动混合到学说实体中。 $meterEntityManager->getRepository(Entity\Meter::class)$meterEntityManager->getConnection() 使用的连接似乎不一致。为什么是这样?这是否与使用不同连接但共享相同实体映射的实体管理器有关?

这里的基本问题是 ServiceEntityRepository class 遍历实体管理器列表并使用支持给定实体的第一个。这很好,除非您碰巧拥有多个实体管理器支持的实体。解决方案是 "old school" 并从 EntityRepository class 扩展,而不是基本上是容器感知的 ServiceEntityRepository。

use Doctrine\ORM\EntityRepository;
class MeterRepository extends EntityRepository
{
    // Note: Do not override the constructor here

您还必须将 App\Repository 目录添加到 services.yaml 中的排除目录列表中。

ServiceEntityRepository 的原因是允许 Symfony 容器自动装配存储库并将它们直接注入到其他服务中。如果他们愿意,它还允许开发人员将额外的依赖项注入存储库。