Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop Doctrine2 ORM不保存对日期时间字段的更改_Oop_Doctrine Orm_Encapsulation - Fatal编程技术网

Oop Doctrine2 ORM不保存对日期时间字段的更改

Oop Doctrine2 ORM不保存对日期时间字段的更改,oop,doctrine-orm,encapsulation,Oop,Doctrine Orm,Encapsulation,我有一个用户实体: 使用条令\ORM\Mapping作为ORM; /** *示例bundle\Entity\User * *@ORM\Entity() */ 类用户 { // ... /** *@ORM\Column(type=“service\u expires\u at”,type=“date”,nullable=true) */ 私人$service于到期日; 公共函数getServiceExpiresAt() { return$this->service\u expires\u在; }

我有一个用户实体:

使用条令\ORM\Mapping作为ORM;
/**
*示例bundle\Entity\User
*
*@ORM\Entity()
*/
类用户
{
// ...
/**
*@ORM\Column(type=“service\u expires\u at”,type=“date”,nullable=true)
*/
私人$service于到期日;
公共函数getServiceExpiresAt()
{
return$this->service\u expires\u在;
}
公共函数setServiceExpiresAt(\DateTime$service\u expires\u at)
{
$this->service\u expires\u at=$service\u expires\u at;
}
}
当我更新用户的
服务到期时间
如下时,更新的
服务到期时间
保存回数据库:

$date=$user->getServiceExpireSet();
变量转储($date->format('Y-m-d'));//2013-03-08
$date->modify(“+10天”);
变量转储($date->format('Y-m-d'));//2013-03-18
$user->setServiceExpiresAt($date);
$em->persist($user);
$em->flush();
但是,如果我将一个新的
DateTime
对象传递给
service\u expires\u,则更新后的值将正确保存:

$date=$user->getServiceExpireSet();
$date->modify(“+10天”);
$user->setServiceExpireSet(新建\DateTime($date->format('Y-m-d'));
$em->persist($user);
$em->flush();

为什么会发生这种情况?

ExampleBundle\Entity\User\getServiceExpiresAt()
返回的
DateTime
实例与存储在实体本身中的对象相同,因此会中断

基本上,这意味着在包含对象的实体属性的情况下,如果对象实例没有更改,ORM不会检测到更改

严格地说,以下是正确的:

$dateTime1=new\DateTime('@0');
$dateTime2=new\DateTime('@0');
$dateTime3=$dateTime1;
var_dump($dateTime1!=$dateTime2);//true
var_dump($dateTime1==$dateTime3);//true
$dateTime1->修改(“+1天”);
var_dump($dateTime1==$dateTime3);//true
这是OOP编程新手中的一个非常常见的错误,可以通过修复getter和setter来快速解决,这样原始实例就永远不会在对象之外共享,如以下示例所示:

公共函数getServiceExpiresAt()
{
返回克隆$this->service\u expires\u在;
}
公共函数setServiceExpiresAt(\DateTime$service\u expires\u at)
{
$this->service\u expires\u at=克隆$service\u expires\u at;
}
这也将解决您的ORM问题

另外,请注意,这修复了逻辑中可能存在的漏洞。例如,以下代码有缺陷且难以调试(当应用当前损坏的getter/setter时):

$bankTransaction1=$someService->getTransaction(1);
$bankTransaction2=$someService->getTransaction(2);
//泄漏!现在两个对象引用同一个DateTime实例!
$bankTransaction2->setDateTime($bankTransaction1->getDateTime());
//臭虫!现在你的两个对象都被修改了!
$bankTransaction1->getDateTime()->修改(“+1天”);

因此,不管问题中的ORM部分是什么,请不要破坏封装。

我在尝试插入具有过去日期的实体时遇到了完全相同的问题(我也在尝试将旧数据库迁移到具有其数据的新模式)

我尝试在setter和getter中克隆对象,但没有用。原则2保存当前日期。检查架构,字段为日期时间而不是时间戳,默认值为null

这怎么可能

编辑:

请原谅我不够注意,我的同事dev添加了一个预科活动:

/**
 * @ORM\PrePersist
 */
function onPrePersist() {
    $this->created_at = new \DateTime('now');
}

考虑将类用于日期/时间属性。因此,请注意DateTimeImmutable不是DateTime的一个实例。

答案非常详细,并指出了确切的问题!感谢您的努力。这让我发疯了!您应该考虑到,这对所有字段都不是一个好主意。如果您与即使是两个实体克隆对象,也会在您触摸代理时触发延迟加载。这可能会破坏您的性能在这些情况下,性能几乎总是次要的:如果您希望这类操作的性能,请直接在数据库级别执行复制操作(通过
INSERT…SELECT…
)我遇到了这个问题,并考虑在事务中包装persist flush(
beginTransaction
/
commit
)-它起作用了。而且-本地环境(xampp)中没有问题,只有在prod linux中才有问题。这种行为是否取决于环境设置?