与非实体关联的实体

时间:2016-09-19 17:27:16

标签: symfony doctrine-orm

我有一个包含2个实现的接口SupplierInterfaceB2BSupplier(一个Doctrine实体),RetailSupplier(一个静态对象)。

<?php
namespace MyBundle\Model;

interface SupplierInterface {

    const B2B = 'B2B';
    const RETAIL = 'Retail';

    /**
     * @return string
     */
    public function getSupplierType();

    /**
     * @return string
     */
    public function __toString();
}

另一个实体SupplySupplier有多对一的关系。通常这不成问题。但由于RetailSupplier不是一个学说实体,我对如何继续下去感到有点沮丧。

Supply看起来像这样:

<?php

namespace MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Blameable\Traits\BlameableEntity;
use Gedmo\Timestampable\Traits\TimestampableEntity;

/**
 * Supply
 *
 * @ORM\Table(name="cir_supply")
 * @ORM\Entity()
 */
class Supply
{
    use BlameableEntity;
    use TimestampableEntity;

    /**
     * @var int
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="B2BSupplier")
     * @ORM\JoinColumn(name="supplier_id", referencedColumnName="id", nullable=true)
     */
    protected $supplier; // <-- PROBLEM, since supplier could be B2BSupplier entity, or it could be vanilla object RetailSupplier

    /**
     * @ORM\ManyToOne(targetEntity="Chemical", inversedBy="supplies")
     * @ORM\JoinColumn(name="chemical_id", referencedColumnName="id", nullable=false)
     */
    protected $chemical;

    /**
     * @ORM\Column(name="external_id", type="string")
     */
    protected $externalId;

//getters and setters ...

}

如果该关系可能并非始终有效,如何指定Doctrine关系?

1 个答案:

答案 0 :(得分:2)

根据我的经验,我99%肯定你不能在当前的设置中做你想做的事。话虽如此,我可以想到一些解决方法。在我进入变通办法之前。您应该考虑是否真的想要“供应商”上的OneToOne关系,或者ManyToOne会更好地运作。 OneToOne有一些延迟加载问题,而且使用ManyToOne可以更好地解决方法3。

解决方法1:

  1. 删除关系并使供应商归档包含id,而不定义关系。
  2. 扩展SupplierRepository'find'方法以处理id为的情况 2.1'null'在女巫案件中没有任何关系它返回RetailSupplier 2.2调用parent :: find用于所有其他情况 2.3可选:如果需要空关系,则将2.1更改为使用'0'而不是null(添加con 3)
  3. 优点:

    1. 从您当前的设置中快速实现
    2. 保留数据库外键(如果忽略步骤2.3)
    3. 缺点:

      1. 'find'方法的隐藏行为
      2. 你放弃了你的学说关系
      3. 不适用于其他类型的供应商
      4. 信息来源在应用和数据库之间分配
      5. 如果需要执行步骤2.3,则会丢失数据库foraign键('0'将不是一个foraign键)
      6. 解决方法2:

        1. 如果$ this-&gt; supplier为null,则修改getSupplier以返回RetailSupplier
        2. 如果$ supplier是RetailSupplyer的实例
        3. ,则修改setSupplier以设置null
        4. Optinal:将前两个步骤改为处理'0'作为RetailSupplyer,将'null'改为无关系
        5. 优点:

          1. 从您当前的设置中快速实现
          2. 保留数据库外键(如果忽略第3步)
          3. 保持学说关系
          4. 缺点:

            1. setter和getter的隐藏行为
            2. 不适用于其他类型的供应商
            3. 如果需要第3步,则会丢失数据库foraign键('0'将不是一个foraign键)
            4. 信息来源在应用和数据库之间分配
            5. 解决方法3 (学说继承映射):

              1. 创建一个抽象(名为Supplier),这将由RetailSupplyer和B2BSupplier继承
              2. 将继承元数据添加到此类
              3. 的供应商摘要中
              4. 为RetailSupplyer创建一个实体,并创建一个数据库表,其中包含一行(第一个RetailSupplier)
              5. 更改数据库以匹配继承映射设置(有关详细信息http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html
              6. 在$ supplier上更改与ManyToOne的关系,并将其指向供应商
              7. 优点:

                1. 信息来源只是数据库
                2. 代码中没有隐藏行为
                3. 可扩展至其他类型的供应商和其他更多零售供应商
                4. 缺点:

                  1. 从您当前的设置(数据库更改,新的学说设置,可能是一些重构)更难实现
                  2. 优点/缺点:根据所选的继承类型,您可以在数据库中使用完整的关系路径(使用foraign键),或者您可以没有任何关系。这取决于您;)在阅读继承映射的文档之后。

                    PS:如果我不得不选择我会选择解决方法3.它是最难实现的,但是可靠的。

                    希望这有助于和快乐的编码

                    Alexandru Cosoi