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)
我没有schema在User实体上使用该属性,因为我的实体管理器配置为使用其数据库,所以它没有用。我以User这种方式建立关系:
/**
* @ORM\ManyToMany(targetEntity="[...]")
*/
private $sites;
Run Code Online (Sandbox Code Playgroud)
非常简单。在代码方面,它有效,关系有效。
在数据库方面,这是不对的,因为user_site由doctrine生成的表只有一个(对于用户)外键:它不包含第二个数据库的外键。该字段存在,具有索引,但没有外键。
如果我自己添加外键,则每次我执行php bin/console doctrine:schema:update --dump-sql“学说”时都希望将其删除。
问题是: 如何使学说创建第二个外键? 或者,如果不可能,如何使学说忽略我自己创建的学说?
感谢@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)