【问题标题】:Deep clone Doctrine entity with related entities具有相关实体的深度克隆 Doctrine 实体
【发布时间】:2020-01-09 01:59:22
【问题描述】:

我创建了一个实体A,OneToMany 与B 有关系,OneToMany 与C 有关系。

我必须克隆这个 A 实体并将其设置在具有新 ID 的数据库中。此外,所有深层关系也应该使用新的 id 进行克隆。

我尝试过将A id 设置为null:

$A = clone $A_original;
$A->setId(null);
$em->persist($A);

它在A 表中创建新记录,但不在B 和C 中。

如何制作A实体的完整副本?

【问题讨论】:

    标签: doctrine-orm symfony-2.1


    【解决方案1】:

    您必须在您的实体中实现 __clone() 方法,将 id 设置为 null 并在需要时克隆关系。因为如果您将 id 保留在相关对象中,它会假定您的新实体 A 与现有实体 B 和 C 有关系。

    A的克隆方法:

    public function __clone() {
        if ($this->id) {
            $this->setId(null);
            $this->B = clone $this->B;
            $this->C = clone $this->C;
        }
    }
    

    B 和 C 的克隆方法:

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

    https://groups.google.com/forum/?fromgroups=#!topic/doctrine-user/Nu2rayrDkgQ

    https://doctrine-orm.readthedocs.org/en/latest/cookbook/implementing-wakeup-or-clone.html

    根据 coder4show 的注释,在 A 上显示 OneToMany 关系的克隆方法,其中 $this->M 是 OneToMany,因此是 ArrayCollection:

    public function __clone() {
        if ($this->id) {
            $this->setId(null);
    
            // cloning the relation M which is a OneToMany
            $mClone = new ArrayCollection();
            foreach ($this->M as $item) {
                $itemClone = clone $item;
                $itemClone->setA($this);
                $mClone->add($itemClone);
            }
            $this->M = $mClone;
        }
    }
    

    【讨论】:

    • @coder4show 那是因为您正在克隆 ArrayCollection 而不是其中的元素。我为 OneToMany 关系添加了一个克隆方法。
    • 在此示例中,OneToMany 关系将不会正确克隆,因为克隆的相关实体仍然引用旧实体。有关工作示例,请参阅 this answer
    • @Richard 谢谢你,你是对的。我已经更新了示例以使其正常工作。
    • 使用$this->setId(null)而不是$this->id = null有什么特别的原因吗?
    • @PierredeLESPINAY 如果您有一个 setter,我建议您使用它,因为在更改 id 时可能会触发其他一些逻辑。除此之外,我认为没有特别的理由使用 setter。对于克隆,它应该具有相同的效果。
    【解决方案2】:

    还有一个模块可以做到这一点,称为 DeepCopy:

    https://github.com/myclabs/DeepCopy

    $deepCopy = new DeepCopy();
    $myCopy   = $deepCopy->copy($myObject);
    

    您还可以添加过滤器来自定义复制过程。

    【讨论】:

    • 嗨@Ben 你能看看this
    • 我发现这个问题令人难以置信,而且使用你自己的 clone 方法会更快
    【解决方案3】:

    我无法使用 DeepClone(它需要 php 7.1+),所以我在实体 __clone 方法中创建了更简单的克隆关系的方法

    $this->tags = new ArrayCollection($this->tags->toArray());
    

    【讨论】:

    • 完美!有用。我正在使用可迭代的,所以它看起来像:$this->foos = \iterable_to_array($this->foos);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-04
    • 2019-02-27
    • 1970-01-01
    • 2016-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多