跳到内容

如何使用多个实体管理器和连接

编辑此页

你可以在 Symfony 应用中使用多个 Doctrine 实体管理器或连接。如果你正在使用不同的数据库,甚至是具有完全不同实体集合的供应商,这是非常有必要的。换句话说,一个连接到一个数据库的实体管理器将处理一些实体,而另一个连接到另一个数据库的实体管理器可能会处理其余的实体。也可以使用多个实体管理器来管理一组通用的实体,每个实体管理器都有自己的数据库连接字符串或单独的缓存配置。

注意

配置多个实体管理器并不复杂,但它更高级,通常不是必需的。在添加此复杂性层之前,请确保你确实需要多个实体管理器。

警告

实体不能跨不同的实体管理器定义关联。如果你需要这样做,有一些替代方案,它们需要一些自定义设置。

以下配置代码展示了如何配置两个实体管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# config/packages/doctrine.yaml
doctrine:
    dbal:
        connections:
            default:
                url: '%env(resolve:DATABASE_URL)%'
            customer:
                url: '%env(resolve:CUSTOMER_DATABASE_URL)%'
        default_connection: default
    orm:
        default_entity_manager: default
        entity_managers:
            default:
                connection: default
                mappings:
                    Main:
                        is_bundle: false
                        dir: '%kernel.project_dir%/src/Entity/Main'
                        prefix: 'App\Entity\Main'
                        alias: Main
            customer:
                connection: customer
                mappings:
                    Customer:
                        is_bundle: false
                        dir: '%kernel.project_dir%/src/Entity/Customer'
                        prefix: 'App\Entity\Customer'
                        alias: Customer

在这种情况下,你定义了两个实体管理器,分别命名为 defaultcustomerdefault 实体管理器管理 src/Entity/Main 目录中的实体,而 customer 实体管理器管理 src/Entity/Customer 中的实体。你还定义了两个连接,每个实体管理器一个,但是你可以自由地为两者定义相同的连接。

警告

当使用多个连接和实体管理器时,你应该明确指定你想要的配置。如果你确实省略了连接或实体管理器的名称,则会使用默认值(即 default)。

如果你为默认实体管理器使用了除 default 之外的其他名称,你将需要在 prod 环境配置和 Doctrine migrations 配置(如果你使用的话)中重新定义默认实体管理器

1
2
3
4
5
6
# config/packages/prod/doctrine.yaml
doctrine:
    orm:
        default_entity_manager: 'your default entity manager name'

# ...
1
2
3
4
# config/packages/doctrine_migrations.yaml
doctrine_migrations:
    # ...
    em: 'your default entity manager name'

当使用多个连接来创建数据库时

1
2
3
4
5
# Play only with "default" connection
$ php bin/console doctrine:database:create

# Play only with "customer" connection
$ php bin/console doctrine:database:create --connection=customer

当使用多个实体管理器来生成迁移时

1
2
3
4
5
6
7
# Play only with "default" mappings
$ php bin/console doctrine:migrations:diff
$ php bin/console doctrine:migrations:migrate

# Play only with "customer" mappings
$ php bin/console doctrine:migrations:diff --em=customer
$ php bin/console doctrine:migrations:migrate --em=customer

如果你在请求实体管理器时确实省略了实体管理器的名称,则会返回默认实体管理器(即 default

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/Controller/UserController.php
namespace App\Controller;

// ...
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;

class UserController extends AbstractController
{
    public function index(ManagerRegistry $doctrine): Response
    {
        // Both methods return the default entity manager
        $entityManager = $doctrine->getManager();
        $entityManager = $doctrine->getManager('default');

        // This method returns instead the "customer" entity manager
        $customerEntityManager = $doctrine->getManager('customer');

        // ...
    }
}

当使用 framework bundle 时,实体管理器也受益于 自动装配别名。例如,要注入 customer 实体管理器,请使用 EntityManagerInterface $customerEntityManager 类型提示你的方法。

你现在可以像以前一样使用 Doctrine - 使用 default 实体管理器来持久化和获取它管理的实体,并使用 customer 实体管理器来持久化和获取它的实体。

同样适用于仓库调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/Controller/UserController.php
namespace App\Controller;

use AcmeStoreBundle\Entity\Customer;
use AcmeStoreBundle\Entity\Product;
use Doctrine\Persistence\ManagerRegistry;
// ...

class UserController extends AbstractController
{
    public function index(ManagerRegistry $doctrine): Response
    {
        // Retrieves a repository managed by the "default" entity manager
        $products = $doctrine->getRepository(Product::class)->findAll();

        // Explicit way to deal with the "default" entity manager
        $products = $doctrine->getRepository(Product::class, 'default')->findAll();

        // Retrieves a repository managed by the "customer" entity manager
        $customers = $doctrine->getRepository(Customer::class, 'customer')->findAll();

        // ...
    }
}

警告

一个实体可以由多个实体管理器管理。但是,当在你的自定义仓库中从 ServiceEntityRepository 扩展时,这会导致意外的行为。ServiceEntityRepository 始终使用为该实体配置的实体管理器。

为了解决这种情况,请扩展 EntityRepository 而不是再依赖自动装配

1
2
3
4
5
6
7
8
9
// src/Repository/CustomerRepository.php
namespace App\Repository;

use Doctrine\ORM\EntityRepository;

class CustomerRepository extends EntityRepository
{
    // ...
}

现在你应该始终使用 ManagerRegistry::getRepository() 获取此仓库。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可协议获得许可。
目录
    版本