学说:两个数据库中两个实体之间的关系

时间:2017-02-23 13:42:24

标签: mysql doctrine-orm doctrine symfony

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

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

我认为Doctrine没有处理这个问题,至少不是以原生的方式处理。无论如何要执行此操作,我在表定义中使用schema属性。

假设我有这两个实体:

/**
 * @ORM\Table(schema="bdd2", name="site")
 */
class Site {}

/**
 * @ORM\Table(name="user")
 */
class User {}

我没有在schema实体上使用User属性,因为我的实体管理器被配置为使用其数据库,所以它没用。我用User这样建立了关系:

/**
 * @ORM\ManyToMany(targetEntity="[...]")
 */
private $sites;

非常简单。 在代码方面,它可以正常工作,这种关系是有效的。

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

如果我自己添加外键,每次执行php bin/console doctrine:schema:update --dump-sql时都要删除它。

问题是: 如何让学说创建第二个外键? 或者如果不可能,我怎样才能使学说无视我自己制作的学说?

1 个答案:

答案 0 :(得分:0)

Thx到@ste answer,有一个让Doctrine为另一个数据库创建外键的解决方案。

我们必须使用Doctrine event listener功能将自己的外键注入Doctrine生成模式管道。

在我的symfony服务配置下面:

app.services.doctrine_foreign_keys:
    class: AppBundle\Services\DoctrineForeignKeys
    tags:
        - {name: doctrine.event_listener, event: postGenerateSchema }

服务本身:

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
                            );
                    }
                }
            }
        }
    }
}