我正在使用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
时都要删除它。
问题是: 如何让学说创建第二个外键? 或者如果不可能,我怎样才能使学说无视我自己制作的学说?
答案 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
);
}
}
}
}
}
}