在我的应用程序中,我有一个有 8 个插槽的雪茄雪茄盒实体。我希望每个老虎机都包含数百种雪茄中的任何一种实例。我可以为一个雪茄盒在雪茄插槽中添加一支雪茄一次,但我不能换成不同的雪茄盒并将相同的雪茄添加到插槽1。我在想,在不同的雪茄盒中,这肯定不是问题,但现在我得到了例外"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
*
* @ORMTable(name="humidor")
* @ORMEntity(repositoryClass="AppBundleRepositoryHumidorRepository")
*/
class Humidor
{
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="name", type="string", length=255, nullable=true)
*/
private $name;
/**
* @ORMManyToOne(targetEntity="UserBundleEntityUser", inversedBy="humidors")
* @ORMJoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_1", referencedColumnName="id")
*/
private $slot1;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_2", referencedColumnName="id")
*/
private $slot2;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_3", referencedColumnName="id")
*/
private $slot3;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_4", referencedColumnName="id")
*/
private $slot4;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_5", referencedColumnName="id")
*/
private $slot5;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_6", referencedColumnName="id")
*/
private $slot6;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_7", referencedColumnName="id")
*/
private $slot7;
/**
* @ORMOneToOne(targetEntity="Cigar")
* @ORMJoinColumn(name="slot_8", referencedColumnName="id")
*/
private $slot8;
然后是我的雪茄实体
/**
* Cigar
*
* @ORMTable(name="cigar")
* @ORMEntity(repositoryClass="AppBundleRepositoryCigarRepository")
* @ORMHasLifecycleCallbacks()
*/
class Cigar
{
/**
* @ORMPrePersist()
*/
public function onPrePersist(){
$this->setName($this->getManufacturer()->getName() . " " . $this->getVariant());
}
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var int
*
* @ORMColumn(name="gauge", type="integer")
*/
private $gauge;
/**
* @var string
*
* @ORMColumn(name="body", type="string", length=255)
*/
private $body;
/**
* @var string
*
* @ORMColumn(name="wrapper_country", type="string", length=255)
*/
private $wrapperCountry;
/**
* @var string
*
* @ORMColumn(name="variant", type="string", length=255)
*/
private $variant;
/**
* @var string
*
* @ORMColumn(name="description", type="text")
*/
private $description;
/**
* @var string
*
* @ORMColumn(name="filler_country", type="string", length=255)
*/
private $fillerCountry;
/**
* @ORMManyToOne(targetEntity="Manufacturer", inversedBy="cigars")
* @JoinColumn(name="manufacturer_id", referencedColumnName="id")
*/
private $manufacturer;
/**
* @ORMManyToOne(targetEntity="Wrapper", inversedBy="cigars")
* @JoinColumn(name="wrapper_id", referencedColumnName="id")
*/
private $wrapper;
/**
* @ORMManyToOne(targetEntity="Shape", inversedBy="cigars")
* @JoinColumn(name="shape_id", referencedColumnName="id")
*/
private $shape;
/**
* @ORMColumn(type="string")
*
*/
private $image;
/**
* @var string
* @ORMColumn(type="string")
*/
private $name;
由于您具有一对一映射,因此 doctrine 会为这些列创建唯一的索引。让我们考虑这个例子(我只留下了一个插槽,因为它足以用于此示例):
id slot_1
1 11
2 12
这意味着您有 2 支 ID 为11
和12
的雪茄分别分配给雪茄盒1
和2
。这里的slot_1
列上有唯一的索引 - 这保证了任何一支雪茄都不属于两个不同的雪茄盒。
如果尝试切换它们,则会生成以下 SQL 语句:
UPDATE humidors SET slot_1 = 12 WHERE id = 1;
UPDATE humidors SET slot_1 = 11 WHERE id = 2;
不幸的是,第一个语句无法执行,因为数据库不允许雪茄12
同时在雪茄盒1
和2
中。
最简单的解决方案是将一对一关系更改为多对一(在您的$slotX
字段中) - 这将删除唯一的约束,否则它在您的示例中的工作方式相同,因为没有反向关系。此外,由于有 8 个插槽,雪茄不能属于其中的几个(如果我正确理解的话),规则已经不受数据库本身的严格控制。
另一种方法是切换具有临时 null 值等的那些,但对于 doctrine 来说更难,因为您需要两个单独的 flush 语句,并且可以选择手动将它们包装在事务中以避免数据库中的状态不一致。