Hibernate删除子实体

时间:2018-01-27 20:46:32

标签: hibernate jpa

我有一个具有OneToMany列表的实体,定义如下:

   @OneToMany(
         mappedBy = "fieldId",
         cascade = CascadeType.ALL,
         orphanRemoval = true,
         fetch = FetchType.EAGER
   )
   @org.hibernate.annotations.OrderBy(clause = "sequence ASC")
   public List<FieldDefinitionValue> getListOfValues()
   {
      return listOfValues;
   }

当我从列表中删除某个项目时,在保存父实体时,它不会从数据库中删除。

我创建了一个CustomEntityDirtinessStrategy,这可能是因为它无法正常工作的原因。在检查父实体的肮脏时,我将实体报告为脏,即使唯一的更改是删除listOfValues中的一个或多个元素。

在findDirty中,我还将listOfValues报告为脏。

dirty = true响应导致不期望的行为(与主要问题分开,这就是子实体删除根本不起作用的原因) - 对父表进行了不必要的更新调用。所以我怀疑我不应该将父实体本身标记为脏。我这样做是为了让孩子进入移除工作。

知道可能导致儿童移除失败的原因吗?

以下是自定义EntityDirtinessStrategy。我在@DynamicUpdate中使用它,以便Hibernate只包含在其更新语句中实际更改的字段。

public class EntityDirtinessStrategy implements CustomEntityDirtinessStrategy
{
   private final Logger log = Logger.getLogger(EntityDirtinessStrategy.class);

   @Override
   public boolean canDirtyCheck(Object entity, EntityPersister persister, Session session)
   {
      return entity instanceof DirtyAware;
   }

   @Override
   public boolean isDirty(Object entity, EntityPersister persister, Session session)
   {
      return entity instanceof DirtyAware && ((DirtyAware)entity).isDirty();
   }

   @Override
   public void resetDirty(Object entity, EntityPersister persister, Session session)
   {
      if (entity instanceof DirtyAware)
         ((DirtyAware)entity).commitFields();
   }

   @Override
   public void findDirty(Object entity, EntityPersister persister, Session session, DirtyCheckContext dirtyCheckContext)
   {
      if (!(entity instanceof DirtyAware)) return;
      DirtyAware dirtyAware = (DirtyAware)entity;
      dirtyCheckContext.doDirtyChecking(
            attributeInformation -> {
               String propertyName = attributeInformation.getName();
               boolean dirty = dirtyAware.getDirtyFields().contains(propertyName);
               if (dirty) log.debug("Property "+propertyName+" is dirty.");
               return dirty;
            }
      );
   }
}

1 个答案:

答案 0 :(得分:0)

我确定了问题所在。我没有说,因为我没有意识到这很重要,就是在我的setX (List list)方法(对于属性X),我不是简单地存储列表然后将其传回getX方法。

相反,我已将该列表中的内容复制到我的本地列表中。

Hibernate要求实体直接使用setX集合,因为它实现了它提供的集合实现中的所有持久性逻辑。我设计了一种替代方法来检查集合的肮脏(对于持久性不是必需的,而是向我的UI代码识别用户是否修改了实体。)然后修改代码以接受并返回setX中的Hibernate集合和getX方法。现在它有效。