我有一个具有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;
}
);
}
}
答案 0 :(得分:0)
我确定了问题所在。我没有说,因为我没有意识到这很重要,就是在我的setX (List list)
方法(对于属性X),我不是简单地存储列表然后将其传回getX
方法。
相反,我已将该列表中的内容复制到我的本地列表中。
Hibernate要求实体直接使用setX集合,因为它实现了它提供的集合实现中的所有持久性逻辑。我设计了一种替代方法来检查集合的肮脏(对于持久性不是必需的,而是向我的UI代码识别用户是否修改了实体。)然后修改代码以接受并返回setX中的Hibernate集合和getX方法。现在它有效。