【问题标题】:Doctrine 2 update from entity来自实体的教义 2 更新
【发布时间】:2011-08-04 11:59:00
【问题描述】:

是否可以通过以下类似的方式更新实体:

$data       = new ATest();  // my entity
$data->id   = 1;            // id 1 already exists, I just want to update this row
$data->name = "ORM Tested"; // changed the name

$entityManager->persist($data);
$entityManager->flush();

这将插入和更改对象的 id,而不是更新数据库中的现有行。

【问题讨论】:

  • 你怎么可以手动设置id? ID 不是受保护的财产吗?
  • 不,如果你不成功,那就不是

标签: php orm doctrine-orm


【解决方案1】:

您还可以使用getReference 按标识符更新实体属性,而无需检索数据库状态。

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/advanced-configuration.html#reference-proxies

这将建立一个简单的代理来通过 ID 处理实体,而不是实例化 new Entity 或使用 find() 从数据库中显式获取实体,然后可以通过刷新对其进行更新。

$data = $entityManager->getReference('ATest', $id);
$data->setName('ORM Tested');
$entityManager->flush();

这对于更新实体的OneToMany 或ManyToMany 关联特别有用。 例如:$case->addTest($data);

手动设置新实体的标识符通常是不好的做法,即使意图是更新实体也是如此。相反,通常最好让 EntityManager 或 Entity 构造函数建立适当的标识符,例如 UUID。出于这个原因,Doctrine 默认会生成实体,其标识符为私有属性,没有 setter 方法。

【讨论】:

  • 与 ::merge() 的区别是什么?
  • Merge 将实体作为Managed 附加到实体管理器。在 OP 的情况下需要它的原因是该实体没有被管理(detached)。发生这种情况是因为它是 instantiated 并且从未持久化/检索,因为它已经存在(根据 OP)。因此需要更新而不是持久化。因此,在 OP 中,实体管理器尝试保留新对象,但由于它已经存在,所以也无法持久化,并且由于新对象不是 managed,因此也没有发生更新。
【解决方案2】:

你应该调用merge而不是persist:

$data = new MyEntity();
$data->setId(123);
$data->setName('test');

$entityManager->merge($data);
$entityManager->flush();

【讨论】:

  • 我认为有人在这里改变了他的答案,所以我的答案看起来不再很有用......
  • 非托管实体需要合并,例如(在我的情况下)实体是通过反序列化实例化的
  • 感谢@francesco,如何给出像 id='1' 这样的 where 条件
  • @rubin 如果您查看我的示例,那将与 UPDATE my_entity_table SET name = 'test' WHERE id = 123; 一样(除非您像我一样更改 ID,但通常不可能,因为 Doctrine 不会自动在主键)。
【解决方案3】:

或者只获取托管实体而不是一个空实体。

$data = $entityManager->getRepository('ATest')->findOne(1); // ATest is my entitity class
$data->name = "ORM Tested"; // just change the name

$entityManager->persist($data);
$entityManager->flush();

如果实体已经被管理,persist() 将更新它而不是插入一个新的。

【讨论】:

  • 如果一个实体是托管的,则不需要调用persist,persist只是告诉学说开始管理一个实体。在这种情况下,flush 就足够了。
  • 其实是否需要persist这取决于配置
  • 这不是为了更新而对数据库的双重查询吗?
  • @Sejanus 是的。我一直在使用它,并且很想知道一种更有效的方法。
  • @Oshanz 见Tracking Policies
【解决方案4】:

我不得不使用

$entityManager->merge($data)

【讨论】:

  • 请注意,您应该将其复制回 $data。即:$data = $entityManager->merge($data)
  • 你怎么看出来的?我在当前文档中没有看到它。也许它自 2013 年以来发生了变化。doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/…
  • @JeroenDeDauw 在您引用的链接中 // $entity now refers to the fully managed copy returned by the merge operation. 否则 $data 将引用实例化、分离或非托管对象。该过程可以在 2.5 中的 \Doctrine\ORM\UnitOfWork::doMerge 进行验证,它会创建一个新的类实例,否则会从数据库中返回检索到的实体。
  • 如果是@OneToMany 的孩子,这个merge 不起作用
  • merge 功能现已弃用(学说 2.7)
猜你喜欢
  • 2015-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多