Doctrine orm 如何在Doctrine2中将两个表加载到一个对象中?

Doctrine orm 如何在Doctrine2中将两个表加载到一个对象中?,doctrine-orm,Doctrine Orm,例如,我们有一个国家和城市的外部数据库。我们需要能够在以下条件下读取该外部DB: 我们不能以任何方式改变或修改世界数据库。例如,我们不能添加FK 当使用外部数据库时,我们希望保留一个内部引用,例如,对于我们的实体“User”,我们希望保留一个引用,例如User->city 我们希望有一个内部实体CustomCities,用户可以在其中创建自己的城市 这样做的最佳方法是什么 我们尝试了几种选择,但都以这样或那样的方式失败了。一个建议是使用外部引用为只读的@Table,但这不起作用 对于这一点,我们

例如,我们有一个国家和城市的外部数据库。我们需要能够在以下条件下读取该外部DB:

  • 我们不能以任何方式改变或修改世界数据库。例如,我们不能添加FK
  • 当使用外部数据库时,我们希望保留一个内部引用,例如,对于我们的实体“User”,我们希望保留一个引用,例如User->city
  • 我们希望有一个内部实体CustomCities,用户可以在其中创建自己的城市
  • 这样做的最佳方法是什么

    我们尝试了几种选择,但都以这样或那样的方式失败了。一个建议是使用外部引用为只读的@Table,但这不起作用

    对于这一点,我们找到的最接近的解决方案是使用一个中间类,该类表示一个城市对象,但实际上并不包含数据,然后通过本机查询填充该伪对象。然后使用内部逻辑确定请求的项(如User->getCity())是来自City DB还是来自CityCustomDB


    关于如何实现这一点有什么想法吗?

    我猜测了可能的模式,您是否尝试过使用类表继承,以便国家基本上成为您的接口

    interface CountryInterface
    {
        public function getName();
    }
    

    所以你的实体可能看起来像这样

    /**
     * @InheritanceType("JOINED")
     * @DiscriminatorColumn(name="type", type="string")
     * @DiscriminatorMap({
     *     "internal" = "InternalCountry"
     *     ,"external" = "ExternalCountryAlias"
     * })
     */
    abstract class AbstractCountry implements CountryInterface
    {
        protected $id;
    }
    
    class InternalCountry extends AbstractCountry
    {
        protected $name;
    
        public function getName()
        { 
            return $this->name;
        }
    }
    
    ExternalCountryAlias的工作原理类似于ExternalCountry的代理,但我将其命名为Alias,以免与数据映射器代理混淆

    class ExternalCountryAlias extends AbstractCountry
    {
        /**
         * @OneToOne(targetEntity="ExternalCountry")
         * @JoinColumn(name="external_country_id"
         *     ,referencedColumnName="id")
         */
        protected $externalCountry;
    
        public function getName()
        {
            return $this->externalCountry->getName();
        }
    }
    
    ExternalCountry不必从基类扩展

    class ExternalCountry 
    {
        protected $name;
    
        public function getName()
        {
            return $this->name;
        }
    }
    
    因此,当你得到一个国家时,你是在引用基类。因此,假设
    country.id=1
    是内部国家,而
    country.id=2
    是外部国家

    // returns an instance of InternalCountry
    $entityManager->find('AbstractCountry', 1);
    
    // returns an instance of ExternalCountryAlias 
    $entityManager->find('AbstractCountry', 2); 
    

    因为它们都实现了CountryInterface,所以您不必担心它们来自何处,您仍然可以通过调用getName()来访问名称

    我猜测了可能的模式,您是否尝试过使用类表继承,以便国家基本上成为您的接口

    interface CountryInterface
    {
        public function getName();
    }
    

    所以你的实体可能看起来像这样

    /**
     * @InheritanceType("JOINED")
     * @DiscriminatorColumn(name="type", type="string")
     * @DiscriminatorMap({
     *     "internal" = "InternalCountry"
     *     ,"external" = "ExternalCountryAlias"
     * })
     */
    abstract class AbstractCountry implements CountryInterface
    {
        protected $id;
    }
    
    class InternalCountry extends AbstractCountry
    {
        protected $name;
    
        public function getName()
        { 
            return $this->name;
        }
    }
    
    ExternalCountryAlias的工作原理类似于ExternalCountry的代理,但我将其命名为Alias,以免与数据映射器代理混淆

    class ExternalCountryAlias extends AbstractCountry
    {
        /**
         * @OneToOne(targetEntity="ExternalCountry")
         * @JoinColumn(name="external_country_id"
         *     ,referencedColumnName="id")
         */
        protected $externalCountry;
    
        public function getName()
        {
            return $this->externalCountry->getName();
        }
    }
    
    ExternalCountry不必从基类扩展

    class ExternalCountry 
    {
        protected $name;
    
        public function getName()
        {
            return $this->name;
        }
    }
    
    因此,当你得到一个国家时,你是在引用基类。因此,假设
    country.id=1
    是内部国家,而
    country.id=2
    是外部国家

    // returns an instance of InternalCountry
    $entityManager->find('AbstractCountry', 1);
    
    // returns an instance of ExternalCountryAlias 
    $entityManager->find('AbstractCountry', 2); 
    
    因为它们都实现了CountryInterface,所以您不必担心它们来自何处,您仍然可以通过调用getName()来访问名称