【问题标题】:knowing when to call persist知道什么时候打电话坚持
【发布时间】:2011-08-31 20:24:51
【问题描述】:

我使用 Doctrine 2 作为我的 ORM,一切进展顺利,但我一直想知道 EntityManager#persist() 方法。 "Persisting entities" 文档说明了对 persist() 对象 X 的调用:

如果 X 是一个预先存在的托管实体,它会被持久化操作忽略。

这让我相信 persist() 只需要在对象是新对象且尚未保存到数据库时调用。但是,"Deferred Explicit" change tracking policy 的文档说:

... Doctrine 2 仅考虑通过调用 EntityManager#persist(entity) 明确标记为更改检测的实体...

... 听起来像persist() 必须在对象上调用才能完全更新。什么时候应该调用persist()?如果仅在新对象上,无论何时更新实体并让 Doctrine 解决差异时调用它是否会对性能产生重大影响?

【问题讨论】:

    标签: php doctrine-orm


    【解决方案1】:

    使用Deferred Explicit policy(它不是默认策略),您需要在每个修改过的实体上显式调用persist() 以使原则持久化。 (级联持续关联除外。)

    Doctrine 仍然需要将每个属性的新值与原始值进行比较,以了解要更新哪个属性,因此如果您 persist() 太多实体,这可能会影响性能。

    使用default change tracking policy,您只需对尚未由 Doctrine 管理的实体(您使用new 创建的实体)调用persist。使用此策略,当您调用 flush() 时,学说会自动检测哪些实体已更新并需要持久化。

    【讨论】:

    • 请注意,当使用延迟隐式更改跟踪(默认)时,Doctrine 会将原始值与每个属性的新值(到目前为止与延迟显式相同)进行比较UnitOfWork,而不仅仅是你在上面调用 persist() 的那些。
    • 我活了半辈子,直到问题出现时才想到默认策略是延迟显式策略。
    【解决方案2】:

    文档有些误导。在隐式跟踪模式下,所有实体都有一个状态(托管、移除、分离等);通过find() 和类似方法获得的实体(基本上所有不是用new 创建的)已经处于托管状态。在flush() 上,检查所有托管(和删除)实体的更改,并在必要时在数据库中更新。

    在显式跟踪模式下,有一个额外的脏检查列表,persist() 将对象(以及可能关联的对象,取决于级联设置)添加到该列表中。只有脏检查列表上的项目才会被考虑更新。刷新后脏检查列表被清除,因此如果您进行第二次刷新,并再次更改同一对象,则必须再次调用persist()。 (相比之下,托管状态在刷新后保持。)

    您可以在Doctrine\ORM\UnitOfWork类中自己查看详细信息;搜索isChangeTrackingDeferredImplicit / isChangeTrackingDeferredExplicit(在这两种策略下,这些是唯一行为不同的地方)。

    【讨论】:

    • 我有一个分离的实体(通道)来自缓存结果集,我需要将数据添加到 - 仅影响数据表。有没有办法在不合并分离的通道的情况下保留通道的数据?
    • @andig,不确定。我认为您在谈论 this question - 当您真的只想添加一个新的数据实体时,为什么还需要保留通道?
    • 很好的问题。我正在使用遗留代码,但对 Doctrine 还是很陌生。将调查我如何/是否可以直接保留“数据”的 ArrayCollection。如果工作,我会很感激交叉回答,以便我可以投票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2016-12-13
    • 1970-01-01
    相关资源
    最近更新 更多