如何处理不违反唯一约束的查询顺序

时间:2013-11-07 13:34:51

标签: php doctrine-orm

假设我有两个实体NewsTag。他们有一对多的关系。 此外,我对标签表('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列设置了UNIQUE约束。

现在我做了:

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

并获得相同的错误,因为它尝试使用'event'值更新第一个标记,并且已经有重复。

PS:我知道我可以拨打flush两次,但这不是一个好主意。

1 个答案:

答案 0 :(得分:0)

我自己也遇到了这个问题,一直试图了解原因和方法。

  PS:我知道我可以两次拨打同花,但这不是一个好主意。

如果您尝试在单个交易中安全地执行所有DML查询,那只是一个坏主意。

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

  1. 所有实体插入
  2. 所有实体更新
  3. 所有集合删除
  4. 所有收藏更新
  5. 所有实体删除
  6. 我怀疑这种排序背后的目标是满足FK约束。即如果删除实体,则需要先删除对它的所有引用。

    如果您需要按特定顺序执行DML查询,我相信您应该使用事务,如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;
    }