Doctrine 2 многие-ко-многим с MappedSuperclass в Zend Framework 2

Я новичок в 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 здесь? Или есть решение для моего случая?

2 ответа

Вы не можете запросить @MappedSuperClass, Это также упоминается в документации Doctrine2 в главе 6.1. Сопоставленные суперклассы:

Сопоставленный суперкласс не может быть сущностью, он не способен выполнять запросы и является постоянным

Это означает, что вы должны либо изменить целевой объект на что-то запрашиваемое, либо вы должны сделать MachineHasPart к сущности и перейти к наследованию одной таблицы.

Когда я смотрю на вашу структуру базы данных, я бы предложил изменить вашу Machine юридическое лицо, чтобы иметь три независимых отношения для частей. Один для Пояса, один для Цилиндра и один для Гира.

Тогда вместо общего getParts у тебя будет три метода getBelts, getCylinders а также getGears,

Если это действительно не то, что вы хотите, то вы можете оставить комментарий.

ОБНОВИТЬ

Вы можете решить это также с наследованием классов. Сначала сделайте базовый класс Part это также сущность и использовать его в других классах Belt, Cylinder а также Gear:

Часть:

<?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 ...
}

Расширьте этот класс в других ваших частях:

Читать далее в документации Doctrine2 в главе 6.1. Сопоставленные суперклассы (на которые ссылается @Wilt):

... Кроме того, ассоциации "многие ко многим" возможны только в том случае, если сопоставленный суперкласс используется только в одном объекте в данный момент...

Это означает, что в этом случае сопоставление ORM не помогает. Я не могу собрать данные всех трех объектов MachineHasCylinder, MachineHasBelt и MachineHasGear одновременно через MappedSupperclass. Я думаю, что использование DQL или Native SQL - единственное решение этой проблемы.

Другие вопросы по тегам