在生产系统中切换OneToOne关系的所有方

时间:2018-01-25 11:35:18

标签: php symfony doctrine-orm

出于性能原因,我正在重构我们的实体设置。具体来说,我想切换OneToOne关系的拥有方。 (主要是因为我首先把它弄错了......)。

问题:我想在实时系统上执行此操作

问题:最好的方法是什么:

  • 不丢失数据
  • 使用Doctrine Migrations

基本上我想移动reference_id字段及其所有数据,并将其移动到关系的另一端。

非常感谢任何帮助。

以下是两个相关实体的一个示例

<?php

class Auction 
{
    /**
     * @ORM\OneToOne(targetEntity="AuctionParameter", mappedBy="auction", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    protected $auction_parameter;
}

class AuctionParameter
{
    /**
     * @ORM\OneToOne(targetEntity="Auction", inversedBy="auction_parameter")
     */
    protected $auction;
}

拍卖应该保留参考ID而不是参数

1 个答案:

答案 0 :(得分:1)

从您的修改中,我将假设reference_id实际上auction_id拥有auction_parameter

首先,您应该制作一份数据库副本(只需要两个表就足够了)来测试我的脚本。我不完美(远离它),我可能犯了一个错误。

在执行脚本之前,您必须在auction表中添加新列。 我建议在php脚本之外进行(例如通过PphMyAdmin)

ALTER TABLE `auction` ADD `auction_parameter_id` INT(11) NULL;
ALTER TABLE `auction_parameter` MODIFY `auction_id` INT(11) NULL;

然后在两个实体中切换拥有方。

AuctionEntity

class Auction 
{
    /**
     * @ORM\OneToOne(targetEntity="AuctionParameter", inversedBy="auction", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    protected $auction_parameter;
}

AuctionParameterEntity

class AuctionParameter
{
    /**
     * @ORM\OneToOne(targetEntity="Auction", mappedBy="auction_parameter")
     */
    protected $auction;
}

保存它,但还没有更新SQL架构,否则你将失去一切 现在这样做将确保新条目已经在正确的拥有方。

以防万一,您应该转储架构更改,以确保Auction表中的新列将被调用auction_parameter_id
如果没有,请调整上面的第一个SQL查询。

php bin/console doctrine:schema:update --dump-sql

现在auction表已准备好欢迎拥有的密钥,运行此脚本应该可以解决问题:

$pdoLink=null;
$PARAM_HOST='localhost';
$PARAM_USER='db_user';
$PARAM_PASSWD='db_passwd';
$PARAM_DB='db_name';
$PARAM_CHARSET='utf8';
try {
    $pdoLink=new PDO("mysql:host=$PARAM_HOST;dbname=$PARAM_DB;charset=$PARAM_CHARSET", $PARAM_USER, $PARAM_PASSWD);
    $pdoLink->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(Exception $e) {
    echo 'Erreur : '.$e->getMessage().'<br />NР: '.$e->getCode();
    exit();
}
$data=array();
$sth=$pdoLink->prepare(/** @lang MySQL */
    "SELECT `auction_parameter`.`id` AS `owned`, `auction_parameter`.`auction_id` AS `owner`
    FROM `auction_parameter`
    WHERE `auction_parameter`.`auction_id` IS NOT NULL");
if($sth !== false && $sth->execute()) {
    while($row=$sth->fetch(PDO::FETCH_ASSOC)) {
        array_push($data, $row);
    }
    foreach($data as $datum) {
        $sth=$pdoLink->prepare(/** @lang MySQL */
            "UPDATE `auction`
            SET `auction`.`auction_parameter_id`=:owned_side
            WHERE `auction`.`id`=:owner_side");
        $sth->bindParam(':owned_side', $datum['owned'], PDO::PARAM_INT);
        $sth->bindParam(':owner_side', $datum['owner'], PDO::PARAM_INT);
        if($sth !== false) {
            $sth->execute();
        }
    }
}
$sth->closeCursor();
$pdoLink=null;

这应该做你需要的。现在,您所要做的就是使用doctrine更新SQL模式。 (您可能需要手动删除foreign_keyaucion_id列,因为其中包含数据)

php bin/console doctrine:schema:update --force