aro*_*oth 16 java hibernate jpa
问题标题基本上都说明了一切.在JPA/Hibernate中是否可以优雅地阻止从数据库中删除实体?我想要的是将实体标记为"隐藏"而不是实际删除它.
我还希望Cascade保留语义,这样如果我尝试删除拥有某个其他实体集合的实体,则拥有实体和其集合中的每个实体都被标记为隐藏,而我不需要任何额外的工作,超出实现@PreRemove阻止删除的处理程序并将实体标记为隐藏.
这是可能的,还是我需要弄清楚其他方法?
Vin*_*lds 12
在JPA/Hibernate中是否可以优雅地阻止从数据库中删除实体?
是的,只要你避免使用EntityManager.remove(entity)它是可能的.如果您确实使用EntityManager.remove(),那么JPA提供程序将使用相应的SQL DELETE语句标记要删除的对象,这意味着在标记要删除的对象后将无法使用优雅的解决方案.
在Hibernate中,您可以使用@SQLDelete和@Where注释来实现此目的.但是,这对于JPA来说效果不佳,因为EntityManager.find()已知忽略@Where注释中指定的过滤器.
因此,仅JPA解决方案将涉及在实体类中添加标志(即列)以区分数据库中的逻辑删除实体与"活"实体.您需要使用适当的查询(JPQL和本机)来确保逻辑删除的实体在结果集中不可用.您可以使用@PreUpdate和@PrePersist注释挂钩实体生命周期事件,以确保在持久化和更新事件时更新标志.同样,您需要确保不会调用该EntityManager.remove方法.
我建议使用@PreRemove注释来挂钩为删除实体而触发的生命周期事件,但使用实体监听器来防止删除由于下述原因而充满麻烦:
SQL DELETE在逻辑意义上防止发生,则需要在同一事务中保留对象以重新创建它*.唯一的问题是,EntityManager在EntityListener中引用它并EntityManager.persist在侦听器中通过推理调用不是一个好的设计决策.基本原理非常简单 - 您最终可能会在EntityListener中获取不同的EntityManager引用,这只会导致应用程序中出现模糊和混乱的行为.SQL DELETE事务本身发生,那么您必须在EntityListener中抛出异常.这通常最终会回滚事务(特别是如果Exception是RuntimeException或声明为导致回滚的应用程序异常),并且不提供任何好处,因为整个事务将被回滚.如果您可以选择使用EclipseLink而不是Hibernate,那么如果您定义适当的DescriptorCustomizer或使用AdditionalCriteria注释,则可能会有一个优雅的解决方案.这两个似乎都适用于EntityManager.remove和EntityManager.find调用.但是,您可能仍需要编写JPQL或本机查询以考虑逻辑删除的实体.
*这在JPA Wikibook中有关级联持久性主题的概述:
如果删除一个对象以删除它,如果然后在对象上调用persist,它将恢复该对象,并且它将再次变为持久化.如果是有意的话,这可能是期望的,但JPA规范也要求级联持久化的这种行为.因此,如果删除对象,但忘记从级联持久关系中删除对它的引用,则将忽略删除.
| 归档时间: |
|
| 查看次数: |
5828 次 |
| 最近记录: |