Symfony关系映射多对一

时间:2017-04-04 14:40:48

标签: php symfony doctrine relational-database entity-relationship

在我的应用程序中,我有一个雪茄盒实体,有8个插槽。我希望每个插槽能够容纳一个可供选择的数百支雪茄的实例。我可以为一个雪茄盒添加雪茄一次雪茄,但我不能换到不同的雪茄盒并添加相同的雪茄到slot1。我当时认为,在不同的雪茄盒中,它肯定不会成为问题,但我现在得到了例外"An exception occurred while executing 'UPDATE humidor SET slot_1 = ? WHERE id = ?' with params [2, 8]:SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2' for key 'UNIQ_4AE64E7F3CF622F8'"'我不是一个专家,而且我不完全确定如何进行建模这个。任何建议都会很棒。

这是带槽的雪茄盒

    /**
 * Humidor
 *
 * @ORM\Table(name="humidor")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\HumidorRepository")
 */

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

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255, nullable=true)
 */
private $name;

/**
 * @ORM\ManyToOne(targetEntity="UserBundle\Entity\User", inversedBy="humidors")
 * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
 */
private $user;

/**
 * @ORM\OneToOne(targetEntity="Cigar")
 * @ORM\JoinColumn(name="slot_1", referencedColumnName="id")
 */
private $slot1;

/**
 * @ORM\OneToOne(targetEntity="Cigar")
 * @ORM\JoinColumn(name="slot_2", referencedColumnName="id")
 */
private $slot2;

    /**
     * @ORM\OneToOne(targetEntity="Cigar")
     * @ORM\JoinColumn(name="slot_3", referencedColumnName="id")
     */
private $slot3;

    /**
     * @ORM\OneToOne(targetEntity="Cigar")
     * @ORM\JoinColumn(name="slot_4", referencedColumnName="id")
     */
private $slot4;

    /**
     * @ORM\OneToOne(targetEntity="Cigar")
     * @ORM\JoinColumn(name="slot_5", referencedColumnName="id")
     */
private $slot5;

    /**
     * @ORM\OneToOne(targetEntity="Cigar")
     * @ORM\JoinColumn(name="slot_6", referencedColumnName="id")
     */
private $slot6;

    /**
     * @ORM\OneToOne(targetEntity="Cigar")
     * @ORM\JoinColumn(name="slot_7", referencedColumnName="id")
     */
private $slot7;

    /**
     * @ORM\OneToOne(targetEntity="Cigar")
     * @ORM\JoinColumn(name="slot_8", referencedColumnName="id")
     */
private $slot8;

然后是我的雪茄实体

    /**
 * Cigar
 *
 * @ORM\Table(name="cigar")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CigarRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Cigar
{
    /**
     * @ORM\PrePersist()
     */
    public function onPrePersist(){
        $this->setName($this->getManufacturer()->getName() . " " . $this->getVariant());
}

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

/**
 * @var int
 *
 * @ORM\Column(name="gauge", type="integer")
 */
private $gauge;

/**
 * @var string
 *
 * @ORM\Column(name="body", type="string", length=255)
 */
private $body;

/**
 * @var string
 *
 * @ORM\Column(name="wrapper_country", type="string", length=255)
 */
private $wrapperCountry;

/**
 * @var string
 *
 * @ORM\Column(name="variant", type="string", length=255)
 */
private $variant;

/**
 * @var string
 *
 * @ORM\Column(name="description", type="text")
 */
private $description;

/**
 * @var string
 *
 * @ORM\Column(name="filler_country", type="string", length=255)
 */
private $fillerCountry;

/**
 * @ORM\ManyToOne(targetEntity="Manufacturer", inversedBy="cigars")
 * @JoinColumn(name="manufacturer_id", referencedColumnName="id")
 */
private $manufacturer;

/**
 * @ORM\ManyToOne(targetEntity="Wrapper", inversedBy="cigars")
 * @JoinColumn(name="wrapper_id", referencedColumnName="id")
 */
private $wrapper;

/**
 * @ORM\ManyToOne(targetEntity="Shape", inversedBy="cigars")
 * @JoinColumn(name="shape_id", referencedColumnName="id")
 */
private $shape;

/**
 * @ORM\Column(type="string")
 *
 */
private $image;

/**
 * @var string
 * @ORM\Column(type="string")
 */
private $name;

1 个答案:

答案 0 :(得分:0)

由于您具有一对一映射,因此doctrine会为这些列创建唯一索引。让我们考虑一下这个例子(我只留下了一个插槽,因为它足以满足这个例子):

id    slot_1
1     11
2     12

这意味着您有2支雪茄,ID 1112分别分配给雪茄盒12。这里有slot_1栏中的唯一索引 - 这可以保证任何一支雪茄都不属于两种不同的雪茄盒。

如果您尝试切换它们,则会生成以下SQL语句:

UPDATE humidors SET slot_1 = 12 WHERE id = 1;
UPDATE humidors SET slot_1 = 11 WHERE id = 2;

不幸的是,第一个语句无法执行,因为数据库不允许雪茄12同时位于加湿器12中。

最简单的解决方案是将一对一关系更改为多对一(在$slotX字段中) - 这将删除唯一约束,否则它在您的示例中的工作方式与没有反向关系。此外,由于有8个插槽,雪茄不能属于其中的几个(如果我正确理解),规则已经不受数据库本身的严格控制。

另一种方法是切换那些具有临时空值等的方法,但是使用doctrine会更难,因为你需要两个单独的flush语句,并且可选地,在事务中手动将它们包装起来以避免不一致的状态。数据库。