原则不会持久修改数据

问题描述 投票:1回答:2

所以我试图在Doctrine中坚持一个实体。我希望持久化的对象看起来像是从Symfony dump()函数中拉出来的:

Time {#7751 ▼
  -id: 3
  -timeIn: DateTime {#7749 ▶}
  -timeOut: null
  -rateId: Rate {#7761 ▼
    -id: 1
    -amount: "30.00"
    -name: "Technical"
    -projectId: Project {#7756 ▶}
    -groupId: 1
  }
  -description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  -userId: 1
  -status: "Unpaid"
  -total: null
  -cost: "60.00"
  -projectId: Project {#7756 ▼
    -id: 1
    -name: "Acme Corp"
    -description: "Metals Company"
    -contactId: 1
    -organizationId: 1
    -groupId: 1
  }
  -groupId: 1
  }

现在我显然不能坚持这个,因为我的ID中有相应的对象。例如:rateId,projectId等等。为了弥补这一点,在我的clockOut函数中,我运行检查以用它们的ID替换对象以进行存储。请参阅下面的clockOut函数:

public function clockOut($time, $group = null){
    dump($time);
    if(gettype($time) == "object"){
        if(gettype($time->getProjectId())=='object'){
            $time->setProjectId($time->getProjectId()->getId());
        }
        if(gettype($time->getRateId())=='object'){
            $time->setRateId($time->getRateId()->getId());
        }
        $this->persistClockout($time);
    }
    elseif(gettype($time) == "string"){
        if($group == null){
            return false;
        }else {
            $time = $this->findData($group, $time);
            $this->persistClockout($time);
        }
    }else {
        return false;
    }
}

还有一个相应的persistClockout函数可以处理实际的时钟输出和小时计算。虽然我认为这与我遇到的问题没有任何关系,但我还是会把它包括在内,因为它是相关的。

/**
 * Persist time
 */
private function persistClockout($time, $group = null){
    if($time->getTimeOut() == null){
        $time->setTimeOut(new DateTime("Now"));
    }
    $this->hours = $this->hoursCalculate($time->getTimeIn(), $time->getTimeOut());
    $time->setTotal($this->hours);
    dump($time);
    die();
    $this->persist($time);
}

/**
 * Get the amount of hours spent in decimal format.
 */
private function hoursCalculate($past, $present){
    $diff = $present->diff($past);
    $hours = round($diff->s / 3600 + $diff->i / 60 + $diff->h + $diff->days * 24, 2);
    return $hours;
}

现在您可以看到我在命令结束之前运行dump()函数,然后它仍然存在,因为我一直在尝试自己诊断此问题。根据dump()函数,数据如下所示:

Time {#7751 ▼
  -id: 3
  -timeIn: DateTime {#7749 ▶}
  -timeOut: DateTime {#11571 ▶}
  -rateId: 1
  -description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  -userId: 1
  -status: "Unpaid"
  -total: 187.83
  -cost: "60.00"
  -projectId: 1
  -groupId: 1
}

大!这是预期的结果。但问题来自于我开始尝试对数据库进行实际持久化。

An exception occurred while executing 'UPDATE rate SET project_id = ? WHERE id = ? AND group_id = ?' with params [{}, 1, 1]:

Notice: Object of class ProjectBundle\Entity\Project could not be converted to int

虽然我在运行persist函数之前检查了数据,但似乎仍然认为projectId仍然是一个对象,即使我确保将其设置为实际的Id而不是对象,它也会忽略我。

我进一步研究了Symfony剖析器并找到了教条用来更新和查看细节的部分,看看projectId是一个对象吗?即使那不是我传入的内容?

Symfony Profiler SQL update with params listed.

任何人都不知道发生了什么事吗?对于罗嗦的帖子感到抱歉,我只是想告诉大家一些你正在使用的信息。请忽略代码中的dump()和die()函数,我一直在使用它们来尝试和诊断这个,但我很困惑。值得注意的是我已经尝试过像php bin / console cache这样的工厂运行:清除,并重新启动服务器。

提前谢谢堆栈溢出!

编辑:

以下是为 - > persist()列出的代码

    public function persist($entity, bool $flush = true)
{
    $this->manager->persist($entity);

    if ($flush) {
        $this->flush();
    }

    return $this;
}

UPDATE

我尝试运行persist然后单独刷新但是没有用。得到了同样的例外。我老实说这里的人不知所措。

php symfony doctrine
2个回答
0
投票

我想你需要使用这段代码:

$this->flush($time); 

而不是$this->persist($time);


0
投票

我想到了。事实证明,这是一个问题,教条如何识别不同的数据和它认为是相同的。我认为这与效率或缓存或某些事情有关。

无论如何,让我告诉你我是如何得出这个结论的。

我得到的第一个提示是,虽然rateId最初是一个对象,后来被转换为它的相应ID,但它没有像ProjectId那样抛出错误。

其次,我更仔细地检查了dump()函数并发现了一些东西。 (我将重复使用原始帖子中的示例)

Time {#7751 ▼
  -id: 3
  -timeIn: DateTime {#7749 ▶}
  -timeOut: null
  -rateId: Rate {#7761 ▼
    -id: 1
    -amount: "30.00"
    -name: "Technical"
    -projectId: Project {#7756 ▶}  <---- Right Here
    -groupId: 1
  }
  -description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  -userId: 1
  -status: "Unpaid"
  -total: null
  -cost: "60.00"
  -projectId: Project {#7756 ▼  <---- Right Here
    -id: 1
    -name: "Acme Corp"
    -description: "Metals Company"
    -contactId: 1
    -organizationId: 1
    -groupId: 1
  }
  -groupId: 1
  }

Project对象后面的数字是相同的。所以我想出了一个理论,即doctrine将原始引用存储在某个地方的projectId(object)中,然后使用它而不是我继续设置的值作为相应的ID(Int)。

因此,为了测试这个理论,我写了两个函数来“展平”我的对象,从对象树的末尾开始(因为它实际上应该只有3个嵌套对象)到开头。这样,所有引用都匹配,即使它们最终被“删除”。

 /**
 * Undo all object associations and convert them back into their original IDs. 
 * @param object $data
 * @param array $callable
 */
public function flattenObject($data, $callable){
    $sorter = new SortingHelper;
    foreach($callable as $call){
        $getMethod = 'get'.ucfirst($call).'Id';
        $setMethod = 'set'.ucfirst($call).'Id';
        if(method_exists($data, $getMethod)){
            $found = $data->$getMethod();
            if(gettype($found) == 'object'){
                $result = $this->flatten($found, $callable);
                $data->$setMethod($result);
            }
        }
    }
    return $data;
}

/**
 * @param object $data 
 * @param array $callable
 */
private function flatten($data, $callable){
    for($i = 0; $i != count($callable); $i++){
        $getMethod = 'get'.ucfirst($callable[$i]).'Id';
        $setMethod = 'set'.ucfirst($callable[$i]).'Id';
        if(method_exists($data, $getMethod)){
            $result = $data->$getMethod();
            if(gettype($result) == 'object'){
                $data->$setMethod($result->getId());
            }
        }
    }
    return $data->getId();
}

运行flattenObject()函数允许我将对象持久化到数据库中,因为对ID的引用不再是对象。

巴姆。超级恼人的问题解决了。

我希望这会以某种方式帮助将来的某个人。谢谢大家的贡献! :)

© www.soinside.com 2019 - 2024. All rights reserved.