【问题标题】:deep copy of doctrine record教义记录的深拷贝
【发布时间】:2010-08-09 12:04:16
【问题描述】:

我想在一个 symfony 项目中制作一个教义记录的深拷贝/克隆。 现有的 copy($deep) 方法不能与 $deep=true 一起正常工作。

举个例子,让我们看一个课堂课程。这节课有一个开始和结束日期,它们之间有几个休息时间。这间教室在一栋楼里。

课间休息是一对多的关系,所以很多课间休息可以在一节课内。 课程建设是多对一的关系,因此课程只能在 ONE Building 中。

如果我想复制房间,也应该复制休息时间。建筑物应该保持不变(这里没有副本)。

我在网上找到了一些示例,它们创建了一个从 sfDoctrineRecord 扩展并覆盖复制方法的 PHP 类。

我尝试的是:

class BaseDoctrineRecord extends sfDoctrineRecord {
    public function copy($deep = false) {
        $ret = parent::copy(false);
        if (!$deep)
            return $ret;

        // ensure to have loaded all references (unlike Doctrine_Record)
        foreach ($this->getTable()->getRelations() as $name => $relation) {
            // ignore ONE sides of relationships
            if ($relation->getType() == Doctrine_Relation::MANY) {
                if (empty($this->$name))
                    $this->loadReference($name);

                // do the deep copy
                foreach ($this->$name as $record)
                    $ret->{$name}[] = $record->copy($deep);
            }
        }
        return $ret;
    }
}

现在这会导致失败:Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY'

所以我需要将新记录 ($ret) 的 id 设为“null”,因为这应该是一条新记录。我可以/应该在哪里以及如何做?

更新: 该错误已通过以下代码修复:

class BaseDoctrineRecord extends sfDoctrineRecord {
    public function copy($deep = false)  {
        $ret = parent::copy(false);

        if($this->Table->getIdentifierType() === Doctrine_Core::IDENTIFIER_AUTOINC) {
            $id = $this->Table->getIdentifier();
            $this->_data[$id] = null;
        }

        if(!$deep) {
            return $ret;
        }

        // ensure to have loaded all references (unlike Doctrine_Record)
        foreach($this->getTable()->getRelations() as $name => $relation) {
            // ignore ONE sides of relationships
            if($relation->getType() == Doctrine_Relation::MANY) {
                if(empty($this->$name)) {
                    $this->loadReference($name);
                }

                // do the deep copy
                foreach($this->$name as $record) {
                    $ret->{$name}[] = $record->copy($deep);
                }
            }
        }

        return $ret;
    }
}

但是效果不好。在 DoctrineCollection 课程->Breaks 中,所有新的中断都可以。但它们没有保存在数据库中。 我想复制一节课,并把它的时间加 7 天:

foreach($new_shift->Breaks as $break) {
    $break->start_at = $this->addOneWeek($break->start_at);
    $break->end_at = $this->addOneWeek($break->end_at);
    $break->save();
}

如您所见,中断已保存,但似乎它们不在数据库中。

【问题讨论】:

  • 我已经为我的需要编写了一个特定的方法。通用解决方案产生的问题多于解决的问题......好吧,目前它根本没有解决任何问题:)

标签: php symfony1 doctrine clone deep-copy


【解决方案1】:

这对我有用,它是问题代码的变体:

public function realCopy($deep = false) {
    $ret = self::copy(false);

    if(!$deep) {
        return $ret;
    }

    // ensure to have loaded all references (unlike Doctrine_Record)
    foreach($this->getTable()->getRelations() as $name => $relation) {
        // ignore ONE sides of relationships
        if($relation->getType() == Doctrine_Relation::MANY) {
            if(empty($this->$name)) {
                $this->loadReference($name);
            }

            // do the deep copy
            foreach($this->$name as $record) {
                $ret->{$name}[] = $record->realCopy($deep);
            }
        }
    }

    // this need to be at the end to ensure Doctrine is able to load the relations data
    if($this->Table->getIdentifierType() === Doctrine_Core::IDENTIFIER_AUTOINC) {
        $id = $this->Table->getIdentifier();
        $this->_data[$id] = null;
    }

    return $ret;
}

我不敢相信我在 2017 年使用 Doctrine 1.2。

【讨论】:

    猜你喜欢
    • 2012-04-12
    • 2015-01-13
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多