在单个事务中仅刷新某些实体

Flush only certain entities in single transaction

在我的应用程序中,我会在特定时间写入读取模型 table(想想 CQRS)。在这样做的同时,我还必须删除旧的读取模型。所以在任何时候我都需要:

  1. 删除实体 a、b、c
  2. 持久化实体 x、y、z

为了在整个生命周期中保持有效的读取模型,我想将这个过程封装在一个事务中。 Doctrine does provide the necessary means.

但是,我还必须保证在此过程中没有其他实体被刷新。可悲的是,调用 doctrine 的 $em->getConnection()->commit(); 似乎会冲刷整个工作单元。但是根据文档,我必须调用它来完成我的交易。

我不能引入第二个实体管理器来只获取我读取的模型实体,因为它们与其他实体位于同一命名空间中,显然这不是应该使用 doctrine-orm-b​​undle 的方式。

我看到的唯一其他方法是在较低级别上工作并完全绕过 EntityManager 和 UnitOfWork,但我想保证事务完整性并且没有 em/ouw 看不到这样做的方法。

TLDR:您的应用程序的工作方式可能保证更新关注完全可分为两个 独立 集,但这是不寻常且脆弱的(当时通常甚至不正确)做出断言)。正确的建模方法是为每个集合使用单独的 EntityManagers,并通过手动保护它们的互连,将 "how they are independent" 的语义编码到系统中。

详情:

如果我对问题的理解正确,那么您遇到的是设计缺陷。您有两组更新(一组用于读取模型,一组用于其他实体)并且将它们混合(因为您希望两者都在同一个实体管理器中)同时您还想将它们分开(通过单独的事务) .一般来说,这是行不通的。

例如,假设非读取模型实体实例 A 刚刚在内存中创建(因此它还没有 ID),基于此您决定用读取模型实体实例 R 引用它。 R->A 关系在内存中有效,但现在您希望能够仅刷新读取的模型实体,而不能刷新其他实体。 IE。当您尝试 persist+flush R 时,它将引用一个不存在的外键,并且您的 RDBMS 有望使事务失败。在高层次上,这是因为连接的内存图在其 entirety 中应该是一致的数据,并且当您尝试将其有效更改拆分为子集时,您正在重新排列顺序隐含地更改这些更改,这可能会引入暂时的不一致,然后您的事务提交可能就在这样的时刻。

当然,您可能知道一些规则,为什么这样的事情永远不会发生,以及为什么每个集合的一致状态以完全独立于另一集合的方式得到保证。但是随后您需要编写反映这种分离的代码;您可以这样做的方法是使用两个实体管理器。在这种情况下,您的代码将清楚地处理两个不同的事务、它们的分离以及双方的一致性。但即使在这种情况下,为了避免更新冲突,您可能需要制定规则来概述两组之间的单向可见性,这也意味着提交交易的顺序。这是因为连接图中的事务可以嵌套,但不能 "only overlap",因为在每次事务提交时,您都要求 ORM 同步 consistent 的内存数据RDBMS 的事务范围。

我知道您提到您不想使用两个 EM,因为读取模型实体 "are in the same namespace as the other entities and apparently that is not the way the doctrine-orm-bundle is supposed to be used"。

  1. 名称空间并不重要。您可以在两个管理器中单独使用它们。你甚至可以将它们互连,如果你 a) 正确地 merge() 它们和 b) 满足你需要为两个 EM 的交易提供的上述一致性(因为现在他们正在处理 one连通图)。
  2. 您应该通过说 "that is not the way the doctrine-orm-bundle is supposed to be used" 来详细说明您指的是什么 -- 最初的建议可能有误,或者该建议应用于此问题的方式有问题。