我正在使用
MySQL和Doctrine 2(使用Symfony 3).
我想在两个独立的数据库中的两个实体之间建立一个ManyToMany关系.
我认为Doctrine不处理这个问题,至少不是以原生的方式处理.无论如何要执行它,我在表定义上使用schema属性.
假设我有这两个实体:
/**
* @ORM\Table(schema="bdd2", name="site")
*/
class Site {}
和
/**
* @ORM\Table(name="user")
*/
class User {}
我没有在User实体上使用schema属性,因为我的实体管理器被配置为使用它的数据库,所以它没用.我以这种方式在User 1中建立关系:
/**
* @ORM\ManyToMany(targetEntity="[...]")
*/
private $sites;
非常简单.在代码方面,它起作用,关系是有效的.
在数据库方面,它不行,因为doctrine生成的user_site表只有一个外键(对于用户):它不包含第二个数据库的外键.该字段存在,有索引,但不是外键.
如果我自己添加外键,每次我做一个php bin / console doctrine:schema:update –dump-sql Doctrine想要删除它.
问题是 :
如何让学说创建第二个外键?
或者如果不可能,我怎样才能使学说无视我自己创造的那个?
最佳答案 这是我建议的解决方案,昨天在我的评论中我无法正确解释.
当你运行doctrine-schema-update(或doctrine-migrations-diff,见https://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html)时,doctrine会做3件事:
>它从映射信息(例如实体注释)生成模式,然后触发postGenerateSchema事件
>它从当前数据库生成模式(通过反向工程)
>它比较两个生成的模式,并生成第二个模式与第一个模式相同的SQL代码.
因此,如果您操纵第一个模式,您可以避免Doctrine做您不喜欢的事情.
在这个例子中,我有一些实体在db中实际上是VIEWS,而不是TABLES.所以我告诉学说不要生成他们的表和相关表上的所有FKs约束.您可以轻松地从这个工作脚本开始,并适应您的需求.
最好的祝福.
这是AppBundle / Utils / IgnoreTablesListener.php
<?php
namespace AppBundle\Utils;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
class IgnoreTablesListener {
private $ignoredEntities = null;
private $ignoredTables = null;
public function __construct($ignoredEntities) {
$this->ignoredEntities=$ignoredEntities;
$this->ignoredTables=array();
}
/**
* Remove ignored entities from Schema
* This listener is called when the schema as been generated, from entities data mapping (i.e. in doctrine-schema-update or in doctrine:migrations:diff)
*
* @param GenerateSchemaEventArgs $args
*/
public function postGenerateSchema(GenerateSchemaEventArgs $args)
{
$schema = $args->getSchema();
$em = $args->getEntityManager();
$ignoredTables = $this->ignoredTables;
foreach ($this->ignoredEntities as $entityName) {
$ignoredTables[] = strtolower($em->getClassMetadata($entityName)->getTableName());
}
foreach ($schema->getTableNames() as $longTableName) {
$table=$schema->getTable($longTableName);
$table_name=strtolower($table->getShortestName($table->getNamespaceName()));
$fks=$table->getForeignKeys();
foreach ($fks as $fk) {
$foreign_table_name=strtolower($fk->getForeignTableName());
if (in_array($foreign_table_name, $ignoredTables)) { //if the fk points to one of the entities i'm ignoring
$table->removeForeignKey($fk->getName()); //i remove fk constrains from generated schema (NOT FROM MY CURRENT DB!!!)
// dump('removed FK '.$fk->getName().' from '.$table_name.' pointing to '.$foreign_table_name.'.['.implode(', ', $fk->getForeignColumns()).']');
}
}
if (in_array($table_name, $ignoredTables)) { //if i have to ignore the $table_name table
$schema->dropTable($longTableName); //remove the table from generated schema -- NOT FROM DB!!
// dump('removed ignored table/entity '.$longTableName);
}
}
}
}
这是服务配置(app / config / services.yml)
..
app.ignoretableslistener:
class: AppBundle\Utils\IgnoreTablesListener
arguments: ['AppBundle:MyEntityToBeIgnoredBecauseItIsAView1', 'AppBundle:MyEntityToBeIgnoredBecauseItIsAView2']
tags:
- {name: doctrine.event_listener, event: postGenerateSchema }
..