我有一个用户实体:
use Doctrine\ORM\Mapping as ORM;
/**
* ExampleBundle\Entity\User
*
* @ORM\Entity()
*/
class User
{
// ...
/**
* @ORM\Column(type="service_expires_at", type="date", nullable=true)
*/
private $service_expires_at;
public function getServiceExpiresAt()
{
return $this->service_expires_at;
}
public function setServiceExpiresAt(\DateTime $service_expires_at)
{
$this->service_expires_at = $service_expires_at;
}
}
当我按如下方式更新用户的service_expires_at
时,更新后的service_expires_at
值是,而不是保存回数据库的:
$date = $user->getServiceExpiresAt();
var_dump($date->format('Y-m-d')); // 2013-03-08
$date->modify('+10 days');
var_dump($date->format('Y-m-d')); // 2013-03-18
$user->setServiceExpiresAt($date);
$em->persist($user);
$em->flush();
但是,如果我将一个新的DateTime
对象传递给service_expires_at
,更新后的值将被正确保存:
$date = $user->getServiceExpiresAt();
$date->modify('+10 days');
$user->setServiceExpiresAt(new \DateTime($date->format('Y-m-d'));
$em->persist($user);
$em->flush();
为什么会发生这种情况?
发布于 2013-03-19 06:31:54
ExampleBundle\Entity\User#getServiceExpiresAt()
返回的DateTime
实例是存储在实体本身中的相同对象,这破坏了encapsulation。
UnitOfWork in Doctrine ORM applies strict comparison for changesets,这基本上意味着在包含对象的实体的属性的情况下,如果对象实例没有更改,则不会检测到更改。
在严格的比较中,以下是正确的:
$dateTime1 = new \DateTime('@0');
$dateTime2 = new \DateTime('@0');
$dateTime3 = $dateTime1;
var_dump($dateTime1 !== $dateTime2); // true
var_dump($dateTime1 === $dateTime3); // true
$dateTime1->modify('+1 day');
var_dump($dateTime1 === $dateTime3); // true
这在OOP编程的新手中是一个非常常见的错误,可以通过修复getter和setter来快速解决这个问题,这样就不会在对象之外共享原始实例,如以下示例所示:
public function getServiceExpiresAt()
{
return clone $this->service_expires_at;
}
public function setServiceExpiresAt(\DateTime $service_expires_at)
{
$this->service_expires_at = clone $service_expires_at;
}
这也会解决Doctrine ORM的问题。
此外,请注意,这修复了您的逻辑中可能的泄漏。例如,以下代码有buggy且难以调试(当应用当前损坏的getter/setter时):
$bankTransaction1 = $someService->getTransaction(1);
$bankTransaction2 = $someService->getTransaction(2);
// leak! Now both objects reference the same DateTime instance!
$bankTransaction2->setDateTime($bankTransaction1->getDateTime());
// bug! now both your objects were modified!
$bankTransaction1->getDateTime()->modify('+1 day');
所以,不管问题中的ORM部分是什么,请不要破坏封装。
发布于 2014-07-30 17:10:18
考虑对日期/时间属性使用DateTimeImmutable类。因此,请注意,DateTimeImmutable不是DateTime的实例。
发布于 2014-01-23 16:42:53
当我试图插入一个具有过去日期的实体时,我也遇到了完全相同的问题(我也试图将一个旧数据库迁移到包含它的数据的新模式)。
我试图用setter和getter来克隆这个对象,但是没有用。原则2保存当前日期。已检查架构,字段为日期时间而不是时间戳,默认为null。
这怎么可能呢?
编辑:
请原谅我的疏忽,我的同事dev添加了一个prePersist事件:
/**
* @ORM\PrePersist
*/
function onPrePersist() {
$this->created_at = new \DateTime('now');
}
https://stackoverflow.com/questions/15486402
复制相似问题