例如,我有一个实体:
/**
* Serie
*
* @ORM\Table(name="series", uniqueConstraints={@ORM\UniqueConstraint(name="unique_position", columns={"chart_id", "position"})})
*/
class Serie
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var int
*
* @ORM\Column(name="position", type="integer")
*/
private $position;
/**
* @var Chart
*
* @ORM\ManyToOne(targetEntity="Chart", inversedBy="series")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="chart_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
* })
*/
private $chart;
}
具有以下架构:
CREATE TABLE IF NOT EXISTS series (
id INT(11) NOT NULL AUTO_INCREMENT,
chart_id INT(11) NOT NULL,
position INT(11) NOT NULL
PRIMARY KEY (id),
UNIQUE INDEX unique_position (chart_id ASC, position ASC) VISIBLE,
UNIQUE INDEX unique_name (chart_id ASC, name ASC) VISIBLE,
INDEX IDX_582B2D4DBEF83E0A (chart_id ASC) VISIBLE,
CONSTRAINT FK_582B2D4DBEF83E0A
FOREIGN KEY (chart_id)
REFERENCES chart (id)
ON DELETE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
以及以下数据:
|----|----------|----------|
| id | position | chart_id |
|----|----------|----------|
| . | . | . |
| . | . | . |
| 3 | 6 | 2 |
| 6 | 1 | 3 |
| 1 | 2 | 3 |
| 4 | 3 | 3 |
| 5 | 4 | 3 |
| 2 | 1 | 4 |
| . | . | . |
| . | . | . |
|----|----------|----------|
使用对象(即非DQL)时,如何对ID为3的图表执行以下操作:
[当我尝试执行flush()时,出现一个唯一的约束错误。
[不使用Doctrine进行交换操作时,我将ID#1位置临时存储为零,将ID#5位置写入ID#1位置(不再违反唯一约束),然后将ID#1位置写入ID #5位置。
[不使用Doctrine进行删除操作时,我首先删除ID#4,然后使用UPDATE series SET position=position-1 WHERE chart_id=3 AND position > 2
重新排序。
我认识到也许没有办法指示Doctrine执行此操作(尤其是交换操作)。
我是否可以添加一些教义侦听器,该侦听器仅干预选定的案例并实现我在没有教义的情况下所做的工作?
或者也许不应该只使用数据库级唯一索引和信任原则?
某些数据库可以在事务结束时检查唯一约束。在这种情况下,主义ORM可以正常工作。看来MySQL尚不支持此功能。
仅数据库本身可以可靠地强制唯一性。教义中对此的支持微乎其微。
解决方法是将这些操作分为两个阶段。
在原始SQL中,很容易将这些操作放在一个事务中。您也可以创建Doctrine的侦听器,但这要复杂得多。