在 Zend 框架 2 中使用 MappedSuperclass 的 Doctrine 2 多对多

Posted

技术标签:

【中文标题】在 Zend 框架 2 中使用 MappedSuperclass 的 Doctrine 2 多对多【英文标题】:Doctrine 2 many-to-many with MappedSuperclass in Zend framework 2 【发布时间】:2015-08-03 00:12:33 【问题描述】:

我是 Doctrine2 的新手,正在尝试为以下数据库结构创建实体:

我想将所有机器部件作为一个数组放在机器类的一个属性中。我试过这个:

class Machine 
    ....
    /**
     * @var array
     * @ORM\OneToMany(targetEntity="MachineHasPart", mappedBy="machine", cascade="persist", "remove", orphanRemoval=TRUE)
     */
    private $parts;
    ....

    public function getParts () 
        return array_map(
            function ($machineHasPart) 
                return $machineHasPart->getPart();
            ,
            $this->parts->toArray()
        );
    

其中MachineHasPart 是中间实体/表的@MappedSuperclass(如machineHasCylinder 等),但它失败了:

执行“SELECT FROM machineHasPart t0”时发生异常

我应该重组我的数据库以在此处使用 ORM 吗?或者我的情况有解决方案吗?

【问题讨论】:

能否在问题中包含完整的错误文本?我会很有用的。 【参考方案1】:

您无法查询@MappedSuperClass。 Doctrine2 documentation in chapter 6.1. Mapped Superclasses中也提到了这一点:

映射的超类不能是实体,它不可查询且不可持久

这意味着您必须将目标实体更改为可查询的对象,或者您必须将MachineHasPart 设置为实体并更改为single table inheritance。

当我查看您的数据库结构时,我建议将您的 Machine 实体更改为具有三个独立的部件关系。一个用于皮带,一个用于气缸,一个用于齿轮。

然后,您将拥有三个方法 getBeltsgetCylindersgetGears,而不是通用的 getParts

如果这真的不是你想要的,那么你可以发表评论。

更新

你也可以通过类继承来解决它。首先创建一个基类Part,它也是一个实体,并在其他类BeltCylinderGear中使用:

部分:

<?php

namespace Machine\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Part
 *
 * @ORM\Entity
 * @ORM\Table("part")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discriminator", type="string")
 * @ORM\DiscriminatorMap(
 *     "part" = "Part",
 *     "gear" = "Gear",
 *     "cylinder" = "Cylinder",
 *     "belt" = "Belt",
 * )
 * @property int $id
 */
class Part

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

    /**
     * @var Machine
     * @ORM\ManyToOne(targetEntity="Machine\Entity\Machine", inversedBy="parts")
     * @ORM\JoinColumn(name="machine_id", referencedColumnName="id", nullable=true)
     */
    protected $machine;

    /**
     * Get id.
     *
     * @return int
     */
    public function getId()
    
        return $this->id;
    

    /**
     * Set id.
     *
     * @param int $id
     * @return self
     */
    public function setId($id)
    
        $this->id = $id;

        return  $this;
    

    //... add setters and getters for machine as normal ...

在你的其他部分扩展这个类:

腰带:

<?php

namespace Machine\Entity;

/**
 * Belt
 *
 * @ORM\Entity
 */
class Belt extends Part


气缸:

<?php

namespace Machine\Entity;

/**
 * Cylinder
 *
 * @ORM\Entity
 */
class Cylinder extends Part



装备:

<?php

namespace Machine\Entity;

/**
 * Gear
 *
 * @ORM\Entity
 */
class Gear extends Part



现在在您的机器中涉及到如下部分。

机器:

<?php

namespace Machine\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Machine
 *
 * @ORM\Entity
 * @ORM\Table("machine")
 * @property int $id
 */
class Machine

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

    /**
     * Get id.
     *
     * @return int
     */
    public function getId()
    
        return $this->id;
    

    /**
     * Set id.
     *
     * @param int $id
     * @return self
     */
    public function setId($id)
    
        $this->id = $id;

        return  $this;
    

    /**
     * @var Collection
     * @ORM\OneToMany(targetEntity="Machine\Entity\Part", mappedBy="machine")
     */
    protected $parts;

    public function __constuct()
    
        $parts = new ArrayCollection();
    

    /**
     *
     * @return Collection
     */
    public function getParts()
    
        return $this->parts;
    

    //... add setters and getters for parts as normal ...

在你的其他部分扩展这个类:

【讨论】:

感谢您的回复。问题是实际上有超过 3 个实体作为“部分”。因此,不适合为例如的每个实体添加一个方法。 20个零件。我还需要它们按“sort_order”属性排序。 @Sbay 我明天会回复另一个可以满足您需求的解决方案。 谢谢@Wilt,期待。 @Sbay,检查我的更新。如果在实施过程中有任何问题,请发表评论。 感谢@Wilt 的更新。问题:哪个表上的哪一列是行的鉴别器@ORM\DiscriminatorColumn(name="discriminator", type="string") 你能告诉我数据库表应该是什么样子吗?因为您的解决方案似乎假设所有部分都具有相似的属性(事实并非如此)。提前谢谢你。【参考方案2】:

进一步阅读Doctrine2 documentation in chapter 6.1. Mapped Superclasses(@Wilt 引用):

...此外,只有当映射的超类目前仅在一个实体中使用时,多对多关联才是可能的...

这意味着在这种情况下,ORM 映射没有帮助。我无法同时通过 MappedSupperclass 收集所有三个实体 MachineHasCylinder、MachineHasBelt 和 MachineHasGear 的数据。 我认为使用DQL 或Native SQL 是解决此问题的唯一方法。

【讨论】:

DQL 如何帮助您解决这个问题? DQL 是一种用于查询数据库模型的对象查询语言。当您使用 DQL 时,数据库模型本身不会有所不同,因此它无法解决您的问题。

以上是关于在 Zend 框架 2 中使用 MappedSuperclass 的 Doctrine 2 多对多的主要内容,如果未能解决你的问题,请参考以下文章

如何在 zend 框架 2 或 AjaxContext 中使用 ajax?

如何在 zend 框架 2 中呈现页面?

在 Zend 框架 2 中使用 MappedSuperclass 的 Doctrine 2 多对多

如何使用zend框架2在更改下拉值时在输入字段内显示值

使用 Zend 框架 2 将数据插入和更新到两个表(事务)中

Zend 框架 2 - 在布局中添加子视图?