Symfony4 - Doctrine Cross Database加入配置

时间:2018-05-03 08:25:18

标签: doctrine-orm symfony4 cross-database

我需要交叉数据库关系,因为映射问题我不能得到我想要的东西read about this buti。 这是我的情况

git config --global user.signingkey 0A46826A

我的教义.yaml

namespace App\Entity\Utility;

use Doctrine\ORM\Mapping as ORM;
use App\Entity\Crm\User;

/**
 * Description of Test
 *
 * @ORM\Table(name="fgel_utility.fgel_test")
 * @ORM\Entity(repositoryClass="App\Repository\Utility\TestRepository")
 */
class Test
{
     /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;


    /**
     * 
     * @var User
     * 
     * @ORM\ManyToOne(targetEntity="App\Entity\Crm\User")
     * @ORM\JoinColumn(name="user_cod", referencedColumnName="AUCUT") 
     */
    protected $user = null;

    public function getId()
    {
        return $this->id;
    }

    public function getUser(): User
    {
        return $this->user;
    }

    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    public function setUser(User $user)
    {
        $this->user = $utente;
        return $this;
    }
}


namespace App\Entity\Crm;

use Doctrine\ORM\Mapping as ORM;
/**
 * 
 * @ORM\Table(name="crm.USER")
 * @ORM\Entity(repositoryClass="App\Repository\FintelGasDati\AnuteRepository")
 */
class User
{

    /**
     * 
     * @ORM\Id
     * @ORM\Column(name="AUCUT", type="integer", nullable=false)
     */
    protected $codiceCliente;

    # SOME CODE
}

所以他们共享相同的连接(但是不同的em)。连接的用户具有读取/写入两个数据库的权限(但仅用于将模式更改为fgel_utility数据库。两个数据库都存储在SQL Server 2008中。 当我试着去做执行

doctrine:
    orm:
        default_entity_manager: default
        entity_managers:
            #################################
            # Update schema only with this em
            #################################
            default:
                connection: mssql_1
                mappings:
                    Utility:
                        type:     "annotation"    
                        # The directory for entity (relative to bundle path)
                        dir:      '%kernel.project_dir%/src/Entity/Utility'   
                        prefix:   'App\Entity\Utility'
                        alias: Utility
            mssql_crm:
                connection: mssql_1
                mappings:
                    Crm:
                        type: "annotation" 
                        # The directory for entity (relative to bundle path)
                        dir: '%kernel.project_dir%/src/Entity/Crm'   
                        prefix: 'App\Entity\Crm'
                        alias: Crm

我收到此错误

  

班级' App \ Entity \ Crm \ User'在配置的链中找不到   命名空间App \ Entity \ Utility,FOS \ UserBundle \ Model

2 个答案:

答案 0 :(得分:0)

根据此https://github.com/doctrine/doctrine2/issues/6350交叉数据库不支持不同实体管理器(相同连接)之间的连接。

答案 1 :(得分:0)

您实际上可以欺骗Doctrine对MySQL / MariaDB进行跨数据库联接查询,只需在实体的ORM \ Table批注中添加数据库名称前缀即可:

// src/Entity/User.php
@ORM\Table(name="dbname.users")

在所有的SELECT,JOIN语句中,Doctrine都将使用它。

那个蜜蜂说,使用此解决方案,将不会使用DATABASE_URL中的DB_NAME或您的env文件的任何其他值,这可能导致混淆(因为数据库名称应与连接而不是实体连接)

因为您无法解析ORM映射中的动态值,例如“ @ORM \ Table(name =%env(DBNAME)%。users”),但这是如何使用 LoadClassMetadata的示例来自Doctrine的事件来动态地完成这项工作。

类构造函数将Entities命名空间作为第一个参数,并将数据库名称作为第二个参数。

Doctrine运行元数据加载时,它将为每个实体使用元数据类触发回调方法,您可以在其上处理这些值并根据这些值动态设置表名称。

// src/DatabasePrefixer.php
class DatabasePrefixer implements EventSubscriber
{
    private $namespace;
    private $tablePrefix;

    /**
    * @param $namespace string The fully qualified entity namespace to add the prefix
    * @param $tablePrefix string The prefix
    */
    public function __construct($namespace, $tablePrefix)
    {
        $this->namespace = $namespace;
        $this->tablePrefix = $tablePrefix;
    }

    public function getSubscribedEvents()
    {
        return ['loadClassMetadata'];
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();

        if ($this->namespace == $classMetadata->namespace) {
          $classMetadata->setTableName(sprintf('%s.%s', $this->tablePrefix, $classMetadata->table['name']));
        }
    }
}

假设您有一个DB_NAME env变量,请使用Symfony的yaml解析功能以及事件标签来侦听正确的Doctrine事件:在config / services.yml中将该类配置为服务。

    // config/services.yaml
    services:
    [...]
    dbname.prefixer:
    class: App\DatabasePrefixer
    arguments:
        $namespace:   'App\Entity'
        $tablePrefix: '%env(DB_NAME)%'
        tags:
            - { name: doctrine.event_listener, event: loadClassMetadata, lazy: true }