在 Symfony2 中使用同一个包中的两个实体管理器

Posted

技术标签:

【中文标题】在 Symfony2 中使用同一个包中的两个实体管理器【英文标题】:Working with two entity managers in the same bundle in Symfony2 【发布时间】:2012-03-07 20:43:01 【问题描述】:

我正在尝试为同一个捆绑包使用两个实体管理器。我的配置是这样的:

orm:

    default_entity_manager:   default
    entity_managers:
        electra:
            connection:       electra
            mappings:
                XXDemoBundle: ~
        default:
            connection:       default
            mappings:
                XXDemoBundle: ~

有什么方法可以判断哪些实体属于哪个实体管理器?如果我想使用不属于默认实体管理器的表,它现在会崩溃。

更新

这是我的连接配置:

doctrine:
    dbal:
        default_connection:       default
        connections:
            default:
                dbname:           old_project
                user:             root
                password:         123123
                host:             1.1.1.1
                port:             1
            electra:
                dbname:           electra
                user:             root
                password:         123123
                host:             2.2.2.2
                port:             2

orm:
    default_entity_manager:   electra
    entity_managers:
        electra:
            connection:       electra
            mappings:
                XXDemoBundle: ~


        default:
            connection:       default
            mappings:
                XXDemoBundle: ~

【问题讨论】:

请发布一个简单的崩溃示例。您的两个连接都指向同一个数据库?似乎你也应该在那里有 auto_generate_proxy_classes ,也许还有 auto_mapping 但也许没有。尝试“php app/console 原则:mapping:info --em”,第一个,然后是另一个实体管理器。 嗨!我使用具有两个不同连接的两个不同数据库。 mapping:info 说我没有由默认实体管理器处理的实体,我所有的实体都由 Electra 处理。 这意味着您在某个地方遇到了配置问题。请发布您的连接映射。学说:映射:信息应该为两个 em 返回相同的实体列表。确保你有 auto_generate 行并且你在开发模式下工作。 请注意,您的所有实体都可供两位经理使用。由于它们指向不同的数据库,因此不会有任何实际重叠,即您将无法跨数据库加入。 我不确定如何更改标签,但如果它被标记为学说 2,您可能会获得更多视图(并且可能会有所帮助) 【参考方案1】:

要在同一个包中使用多个实体管理器,您必须为每个实体管理器配置映射选项。

http://symfony.com/doc/current/reference/configuration/doctrine.html

示例关闭配置文件

教义: 分贝: 默认连接:默认 连接: 默认: 驱动程序:%database_driver% 主机:%database_host% 端口:%database_port% 数据库名称:%database_name% 用户:%database_user% 密码:%database_password% 字符集:UTF8 第二: 驱动程序:%database_sqlite_driver% 主持人:~ 港口:~ 数据库名称:%database_sqlite_shop_name% 路径:%database_sqlite_shop_name% 用户:~ 密码:~ 字符集:UTF8 形式: auto_generate_proxy_classes: %kernel.debug% default_entity_manager: 默认 实体经理: 默认: 连接:默认 映射: 你的捆绑包: # 你必须指定类型 类型:“注释” # 实体的目录(相对于捆绑路径) 目录:“实体/FirstDb” #前缀 前缀:“Your\Bundle\Entity\FirstDb” 店铺: 连接:第二 映射: 你的捆绑包: 类型:“注释” #这里是连接实体所在的第二条路径 目录:“实体/SecondDb” #前缀 前缀:“Your\Bundle\Entity\SecondDb”

您现在可以使用控制台通过 --em 参数管理您的数据库

例如:更新商店实体管理器的数据库

php app/console doctrine:schema:update --em=shop

从 Your\Bundle\Entity\SecondDb 读取映射信息

例如:更新默认实体管理器的数据库

php app/console doctrine:schema:update   

从 Your\Bundle\Entity\FirstDb 读取映射信息

【讨论】:

谢谢。你的回答很好。应该接受! 谢谢你,很抱歉迟到的评论。 由于这是一个公认的答案,请注意在较新版本的 Symfony 中,您必须转义前缀中的反斜杠,例如:“Your\\Bundle\\Entity\\SecondDb”,否则它不起作用。 指定不存在的目录“Entity/FirstDb”作为Doctrine映射源。【参考方案2】:

好的。试图编辑您的原始帖子,但它正在等待同行评审。不知道这需要多长时间。尝试将您的配置更改为:

doctrine:
    dbal:
        default_connection:       default
        connections:

        default:
            dbname:           old_project
            user:             root
            password:         123123
            host:             1.1.1.1
            port:             1

        # Make an explicit connection just for clarity
        old_project:
            dbname:           old_project
            user:             root
            password:         123123
            host:             1.1.1.1
            port:             1            

        electra:
            dbname:           electra
            user:             root
            password:         123123
            host:             2.2.2.2
            port:             2

    orm:
        # Humor me and add these
        auto_generate_proxy_classes: %kernel.debug%
    #   auto_mapping: true

    default_entity_manager:   electra
    entity_managers:

    # Make an explicit old_project em so default does not confuse us
    old_project:
        connection:       old_project
        mappings:
            XXDemoBundle: ~

    electra:
        connection:       electra
        mappings:
            XXDemoBundle: ~


    default:
        connection:       default
        mappings:
            XXDemoBundle: ~

现在完全清除你的缓存,以确保运行:

php app/console doctrine:mapping:info --em electra
php app/console doctrine:mapping:info --em old_project

您应该得到相同的结果。我在我的系统上对此进行了测试,所以我相当肯定,如果你不这样做,那么你在某处有一些错字。

所以映射信息正在工作。下一步是验证两个数据库是否与您的实体模式匹配。这样做:

php app/console doctrine:schema:update --em electra --dump-sql
php app/console doctrine:schema:update --em old_project --dump-sql

两者都不应该产生任何输出。如果是这样,则意味着您的数据库与您的实体不匹配,需要在查询起作用之前解决(可能使用 --force 选项)。

一旦数据库同步,那么您可能应该使用教义:查询:dql 并对两个管理器进行测试查询。然后回到你的代码。

===========================================

现在已经理解,真正的目标是让两个实体管理器指向同一组实体,但以某种方式表明每个实体管理器都应将自己限制为这些实体中的某个集合。这不是 S2 开箱即用的支持。

您可以查看 Doctrine 手册,了解它如何处理实体元数据,并可能对其进行处理,但这可能会变得复杂。

S2 真正提供的唯一功能是使用映射属性将实体管理器绑定到一个或多个包中的所有实体。如果您想将一个包中的七个实体中的三个与另一个包共享,那么您只需在第二个包中重新创建这些实体。可能通过扩展类以避免代码重复。

我认为您可能想稍微改变一下您的方法。如果您有一组与多个包共享的核心实体,则将它们放在自己的包中。然后每个后续捆绑包都可以添加其他实体。

【讨论】:

用新配置更新了我的答案以尝试 现在,映射似乎很好,我看到两个实体管理器的实体相同。但是,无论我尝试访问电子中的某些内容,都会遇到相同的错误,它说:SQLSTATE [42S22]:找不到列:1054 Unknown column 't0.country_code' in 'field list' 500 Internal Server Error - PDOException the country table在电子数据库中,而不是与默认连接的数据库中 根据两位经理看到相同实体这一事实更新了答案。 好的,但问题是我不想在两个数据库中拥有所有相同的表,我只想使用一些具有默认值的实体,其余的与另一个。我不希望它们以任何方式同步。我只是不明白如何告诉学说哪个实体属于哪个数据库。 修改了我的答案。底线是 S2 不支持您开箱即用的要求。

以上是关于在 Symfony2 中使用同一个包中的两个实体管理器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用doctrine查询symfony2中实体类中的另一个实体

如何在 Symfony2 中单向持久化一对一实体

symfony2 构建表单实体 oneToMany

Symfony2/Doctrine:如何从实体类中持久化一个实体?

Symfony2 和 Doctrine2 :用两个实体填充表单(一个复杂的场景)

如何从 symfony2 中删除实体