为什么实体管理器为每个实体刷新相同的日期? [英] Why Entity Manager flush the same date for each entities?

查看:26
本文介绍了为什么实体管理器为每个实体刷新相同的日期?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 symfony 5.2 中为我的实体制作装置.

I am making fixtures for my entities in symfony 5.2.

其中一个代表带有标题、描述和发行日期的杂志.

One of these represent a magazine with a title, a description and a release date.

我的夹具代码:

class MagazineFixtures extends Fixture
{
    public function load(ObjectManager $manager)
    {
        $faker = Factory::create();

        $intialReleaseDate = new DateTime('1913-04-01');

        for ($i=0; $i < 100; $i++) { 
            $title = $faker->sentence($nbrwords=6, $variableNbWords=true);
            $number = $i + 1;
            // A magazine is release each month.
            $releaseDate = $intialReleaseDate;
            $intialReleaseDate->modify('first day of next month');

            $magazine = new Magazine();
            $magazine
                ->setTitle($title)
                ->setNumber($number)
                ->setReleaseDate($releaseDate)
            ;
            $manager->persist($magazine);
        }

        $manager->flush();
    }
}

问题是当我运行我的装置时,每本杂志都有相同的日期(这是最后一个日期),我通过在 for 循环中打印它们来验证所有日期,并且都是正确的.

The issue is when I run my fixture, each magazine have the same date (which is the last date), I verified all the date by printing them in the for loop and all are correct.

我尝试在 for 循环中移动flush方法并且它起作用了!日期正确保存在数据库中.

I tried to move the flush method in the for loop and it works! The date are correctly saved in the database.

我了解到,当所有实体都被持久化时必须调用flush方法,并且它一直工作到现在.我不明白为什么它在这里不起作用.

I learned that the flush method must be called when all entities are persisted and it worked all the time until now. I don't understand why it doesn't work here.

推荐答案

发生这种情况的原因通常与 flush 方法或实体管理器无关.发生这种情况的原因是因为保存对象的变量不保存对象本身,而是一个标识符(引用自 对象和引用页面):

The reason this is happening has nothing to do with the flush method or the Entity Manager in general. The reason this is happening is because variables holding objects don't hold the object itself, but rather an identifier (quote from the Objects and references page):

PHP 引用是一个别名,它允许两个不同的变量写入相同的值.从 PHP 5 开始,对象变量不再包含对象本身作为值.它只包含一个对象标识符,它允许对象访问者找到实际的对象.当一个对象通过参数发送、返回或分配给另一个变量时,不同的变量不是别名:它们持有指向同一个对象的标识符的副本.

A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.

为了演示,考虑一个简单的案例:

To demonstrate, consider a simple case:

class A
{
    public $b;
}

class B
{
    public $num;
}

$b = new B();
$b->num = 2;
$a = new A();
$a->b = $b;
print_r($a);
$b->num = 4;
print_r($a);

第一个 print_r 将显示以下内容:

The first print_r will show the following:

A Object (
    [b] => B Object (
        [num] => 2
    )
)

第二个将显示:

A Object (
    [b] => B Object (
        [num] => 4
    )
)

即使我们没有对 $a 本身进行任何修改,通过修改(变异)$b,我们已经确保 $a->b 保存更新后的值.

Even though we didn't perform any modifications on $a itself, by modifying (mutating) $b, we've ensured that $a->b holds the updated value.

所以在您的代码中发生的事情是,由于 DateTime 是可变的,通过在每次迭代中修改它,您正在修改分配给每个实体的相同实例.这意味着,在循环结束时,每个实体都将引用修改后的实例,从而导致刷新相同的日期.

So what's happening in your code is, since DateTime is mutable, by modifying it in each iteration you are modifying the same instance that you assign into every entity. That means that, by the end of the loop, every entity will be referencing the modified instance, resulting in the same date being flushed.

解决此问题的解决方案,同时仍允许在循环后进行单个 flush 调用,要么切换到 DateTimeImmutable,它会在修改时创建一个新实例,或者将 DateTime 对象的副本传递到您的实体中.

Solutions to get around this issue, while still allowing a single flush call after the loop, would be either switching to DateTimeImmutable, which creates a new instance when modified or passing a clone of the DateTime object into your entities.

这篇关于为什么实体管理器为每个实体刷新相同的日期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆