1

假设我有两个实体,News并且Tag. 它们具有一对多的关系。我也对标签表有一个独特的约束('news_id', 'name')

现在我现在的状态是:

tags
---------------------
id | news_id | tag
---------------------
1  |       1 | world
2  |       1 | event

如果我做:

$em->remove($tag2);
$em->persist(new Tag($tag2->getNews(), 'event'));

我明白Integrity constraint violation: 1062 Duplicate entry了,因为教义试图在删除旧实体之前插入。当我更新/删除时也会发生同样的情况。是否可以告诉教义首先删除旧实体?还是有更好的解决方案?

另一个例子:

一个简单的表:

tags
---------------------
id | tag
---------------------
1  | world
2  | event

tag列设置了唯一约束。

现在我这样做:

$tags = $em->getRepository('Tag')->findAll();
$tempName = $tags[0]->getName();
$tags[0]->setName($tags[1]->getName());
$tags[1]->setName($tempName);

并得到相同的错误,因为它尝试使用“事件”值更新第一个标签,并且已经存在重复。

PS:我知道我可以打电话flush两次,但这是个坏主意。

4

1 回答 1

0

我自己遇到了这个问题,并且一直试图弄清楚为什么和如何。

PS:我知道我可以跟注两次,但这是个坏主意。

如果您试图在单个事务中安全地执行所有 DML 查询,这只是一个坏主意。

Doctrine 将按以下顺序提交 DML 语句:

  1. 所有实体插入
  2. 所有实体更新
  3. 所有集合删除
  4. 所有收藏更新
  5. 所有实体删除

我怀疑这种排序背后的目标是满足 FK 约束。即如果你删除一个实体,你需要先删除所有对它的引用。

如果您需要按特定顺序执行 DML 查询,我相信您应该使用 Transactions,如Transactions and Concurrency中的 Doctrine 文档中所述。

因此,使用此方法,您调用flush()了两次,但您在单个事务中执行此操作。以下是基于您的标签的示例,假设标签名称是唯一的。

<?php

$em->beginTransaction();
try {
    $tag2 = $em->find(2);
    $tagName = $tag2->getName();
    $newTagWithSameName = new Tag($tagName);

    $em->remove($tag2);
    $em->flush();

    $em->persist($newTagWithSameName);
    $em->flush();

    $em->commit();
} catch (Exception $e) {
    $em->rollback();
    throw $e;
}
于 2017-01-29T12:30:52.033 回答