原则:两个数据库中两个实体之间的关系

Tho*_*lin 5 mysql doctrine symfony doctrine-orm

我正在使用MySQL和Doctrine 2(与Symfony 3)。

我想在两个单独的数据库中建立两个实体之间的ManyToMany关系。

我骑着Doctrine不能解决这个问题,至少不能以一种本机的方式来解决。无论如何要执行该操作,我在schema表定义中使用了属性。

假设我有这两个实体:

/**
 * @ORM\Table(schema="bdd2", name="site")
 */
class Site {}
Run Code Online (Sandbox Code Playgroud)

/**
 * @ORM\Table(name="user")
 */
class User {}
Run Code Online (Sandbox Code Playgroud)

我没有schemaUser实体上使用该属性,因为我的实体管理器配置为使用其数据库,所以它没有用。我以User这种方式建立关系:

/**
 * @ORM\ManyToMany(targetEntity="[...]")
 */
private $sites;
Run Code Online (Sandbox Code Playgroud)

非常简单。在代码方面,它有效,关系有效。

在数据库方面,这是不对的,因为user_site由doctrine生成的表只有一个(对于用户)外键:它不包含第二个数据库的外键。该字段存在,具有索引,但没有外键。

如果我自己添加外键,则每次我执行php bin/console doctrine:schema:update --dump-sql“学说”时都希望将其删除。

问题是: 如何使学说创建第二个外键? 或者,如果不可能,如何使学说忽略我自己创建的学说?

Tho*_*lin 2

感谢@ste 的回答,有一个解决方案可以让 Doctrine 创建另一个数据库的外键。

我们必须使用Doctrine 事件监听器功能将外键自己注入到 Doctrine 生成模式管道中。

下面是我的 symfony 服务配置:

app.services.doctrine_foreign_keys:
    class: AppBundle\Services\DoctrineForeignKeys
    tags:
        - {name: doctrine.event_listener, event: postGenerateSchema }
Run Code Online (Sandbox Code Playgroud)

以及服务本身:

namespace AppBundle\EventListener;

use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;

/**
 * Class DoctrineForeignKeys
 *
 * @package AppBundle\EventListener
 */
class DoctrineForeignKeys
{
    /**
     * Generate foreign keys to other databases
     *
     * @param GenerateSchemaEventArgs $args
     */
    public function postGenerateSchema(GenerateSchemaEventArgs $args)
    {
        $em = $args->getEntityManager();
        $schema = $args->getSchema();
        $mainSchemaName = $args->getSchema()->getName();

        /**
         * @var \Doctrine\ORM\Mapping\ClassMetadata $metaData
         */
        foreach ($em->getMetadataFactory()->getAllMetadata() as $metaData) {
            $schemaName = $metaData->getSchemaName();
            // this is an entity on another database, we don't want to handle it
            if ($schemaName && $schemaName != $mainSchemaName) {
                continue;
            }

            // fetch all relations of the entity
            foreach ($metaData->associationMappings as $field => $mapping) {
                $targetMetaData = $em->getClassMetadata($mapping['targetEntity']);
                $targetSchemaName = $targetMetaData->getSchemaName();
                // the relation is on the same schema, so no problem here
                if (!$targetSchemaName || $targetSchemaName == $mainSchemaName) {
                    continue;
                }

                if (!empty($mapping['joinTable'])) {
                    foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseColumn) {
                        $options = array();
                        if (!empty($inverseColumn['onDelete'])) {
                            $options['onDelete'] = $inverseColumn['onDelete'];
                        }
                        // add the foreign key
                        $schema->getTable($mapping['joinTable']['name'])
                            ->addForeignKeyConstraint(
                                $targetSchemaName.'.'.$targetMetaData->getTableName(),
                                [$inverseColumn['name']],
                                [$inverseColumn['referencedColumnName']],
                                $options
                            );
                    }
                } elseif (!empty($mapping['joinColumns'])) {
                    foreach ($mapping['joinColumns'] as $joinColumn) {
                        // add the foreign key
                        $options = array();
                        if (!empty($joinColumn['onDelete'])) {
                            $options['onDelete'] = $joinColumn['onDelete'];
                        }
                        $schema->getTable($metaData->getTableName())
                            ->addForeignKeyConstraint(
                                $targetSchemaName . '.' . $targetMetaData->getTableName(),
                                [$joinColumn['name']],
                                [$joinColumn['referencedColumnName']],
                                $options
                            );
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)