如何在Doctrine 2中将实体另存为另一行

88
假设我有一个实体$e。是否有一种通用的方法将其存储为另一行,该行具有相同的实体数据但具有另一个主键?
为什么我需要这个:我正在实现某种时间数据库模式,而不是更新行,我只需要创建另一个行。

头脑风暴一下(即未经测试),你试过 $f = clone $e 吗?可能需要实现 __clone() 方法。 - Phil
4
@Phil: 克隆的实体具有相同的主键,因此只会更新同一行。更令人惊讶的是——spl_object_hash(Doctrine用它来识别特定的实例)对于原始对象和克隆对象是相同的,即使它们包含不同的数据。 - zerkms
@Phil:__clone()也没用 - Doctrine使用 $oid = spl_object_hash($entity); 和一些内部映射来获取对象的状态。对于原始的对象和克隆的对象来说,它们的状态都是相同的 - MANAGED - zerkms
1
这不是真的。clone $e 返回另一个实例,因此具有另一个 spl_object_hash() 值。 - Florian Klein
@Florian:你试过那个了吗?还是你认为会是那样?我试过了,并根据我的观察发表了评论。 - zerkms
1
尝试过并且确信。克隆是一个不同的实例,直到您要求UnitOfWork / identityMap注册它,否则此实体将被视为INSERTed。 - Florian Klein
4个回答

185

尝试克隆并向您的实体添加以下方法

public function __clone() {
    $this->id = null;
}

在持久化实体之前,您可能需要分离该实体。我现在没有我的开发机器来测试这个。

$f = clone $e;
$em->detach($f);
$em->persist($f);
$em->flush();

更新

刚刚尝试使用了一个简单的SQLite演示。你不需要做任何事情。以下内容对我而言可以正常工作,无需添加__clone()方法或进行其他额外操作。

$new = clone $old;
$em->persist($new);
$em->flush();

一旦刷新,$new 实体将具有一个新的ID并作为新行保存在数据库中。

从纯模型视角来看,我仍会通过 __clone() 方法将 ID 属性设置为 null。

更新2

深入研究 Doctrine 代码后发现,这是因为生成的代理类使用了这个重要的语句实现了 __clone() 方法。

unset($this->_entityPersister, $this->_identifier);

9
当我尝试使用这种方法时,对原始实体的任何更改都会被持久化到数据库中,并插入一个新记录。这是因为实体管理器仍在管理它。即使我将原始实体分离(detach),它仍会保存更改。我不知道为什么,也不知道如何成功让实体管理器停止管理原始实体(即放弃更改)。$em->refresh($old)$em->detach($old) 都似乎不起作用... - Chadwick Meyer
2
请注意,实现__clone()方法只适用于没有任何关系的平面对象。特别是仅复制不引用其他对象的数据,所有引用将与原始对象相同。 - barbieswimcrew
3
@barbieswimcrew 正确。我有另一个回答处理那种情况。 - Phil
3
如果其他人也遇到了这个问题,只需刷新您的$new entity。使用 $em->flush($new); 而不是 $em->flush(); ,否则两个实体都将保存新数据。 - Josh
2
@Yep_It's_Me 这里是一个未中断的(atm)链接,指向Doctrine文档中有关如何实现克隆或唤醒的内容。 - Dimitry K
显示剩余8条评论

1
clone和detach对我来说很有效。Symfony版本5.4不接受flush()的任何参数。
    $new = clone $discount;
    $new->setId(null);
    $discountRequest = new DiscountRequest();
    $discountRequest->setDiscount($new);
    
    $discountRequest->setOldDiscount($discount->getId());
    $entityManager->persist($discountRequest);
    $entityManager->detach($discount);
    $entityManager->flush();

0

-2

将数据复制到同一类的新对象中并持久化即可。保持简单!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接