我们目前面临着新实体和findDirty拦截器的“问题” - 从我们的角度来看,它看起来像一个bug。然而,它也可能是一个特征 - 因此,对此主题的专业知识和评论表示赞赏。
干杯 克里斯托夫
我们的环境: Hibernate 4.2.7(使用JPA API 2.x)
问题: 我们有两个实体UserBO和InternalOrganizationBO 两个对象之间的关系如下所示。 两个对象都有一个布尔标志'flushUpdates'。 这个'flushUpdate'标志在我们的自定义findDirty实现中进行评估(覆盖EmptyInterceptor.findDirty)。 如果'flushUpdate'为false,则findDirty返回一个空数组。
我们在做什么: 1.我们从数据库中获取UserBO对象(因此处于托管状态) 2.我们创建一个新的InternalOrganizationBO对象 3.我们将UserBO和InternalOrganizationBO的flushUpdates标志设置为false 4.我们为User设置了InternalOrganizationBO对象 5.调用entityManager.flush方法
我们认为是一个错误: entityManager.flush方法正在触发InternalOrganizationBO的SQL INSERT 虽然findDirty方法为两个对象返回一个空数组,但我们没有 为InternalOrganizationBO调用explcit持久化。
(顺便说一句:当两个对象已经存在于数据库中且处于托管状态时,'findDirty'似乎工作正常)
所以问题: 这真的是Hibernate框架应该如何表现的吗? 不应该从findDirty返回的'空数组'阻止插入吗? 还有其他选项可以阻止Hibernate进行插入吗?
---源代码实体类:
@Entity
@SqlResultSetMapping(....)
@Table(schema="...", name="...")
@IdClass(UserBO_PK.class)
public class UserBO extends AbstractBO implements Serializable {
...
@ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.MERGE, CascadeType.DETACH, CascadeType.PERSIST})
@JoinColumn(name=UserBO.INTERNALORGANIZATION_ID)
protected InternalOrganizationBO internalOrganization;
...
@Transient
protected boolean flushUpdates = false;
public boolean isFlushUpdates() {
return flushUpdates;
}
...
}
@Entity
@SqlResultSetMapping(
name="InternalOrganizationBO",
entities = @EntityResult(entityClass=InternalOrganizationBO.class),
columns = { @ColumnResult (name="externalName")})
@Table(schema="...", name="...")
@IdClass(InternalOrganizationBO_PK.class)
public class InternalOrganizationBO extends AbstractBO implements Serializable {
...
@OneToMany(mappedBy="internalOrganization", fetch=FetchType.LAZY, cascade={CascadeType.MERGE, CascadeType.DETACH, CascadeType.PERSIST})
protected List<UserBO> users;
...
@Transient
protected boolean flushUpdates = false;
public boolean isFlushUpdates() {
return flushUpdates;
}
...
}
--- SourceCode TestCase //加载用户对象 UserBO user = entityManager.find(UserBO.class,new UserBO_PK(“testUser”));
//create internal organization
intOrg01 = new InternalOrganizationBO(intOrg01_id);
intOrg01.setCode(intOrg01_code);
intOrg01.setBusinessUnit(BusinessUnitEnum.empty);
//set all flush updates to false
intOrg01.setFlushUpdates(false);
user01.setFlushUpdates(false);
//add intOrg to user
user01.setInternalOrganization(intOrg01);
---自定义impl。对于findDirty:
@Override
public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
/**
* logic impl.
*/
if (entity instanceof AbstractBO) {
if (((AbstractBO) entity).isFlushUpdates()) {
return null;
} else {
logger.info("Ignoring flush for object: " + entity.getClass().getSimpleName() + ", "
+ entity.toString());
return new int[0];
}
}
}
//flush entityManager
//THIS triggers an insert of intOrg ! (no update to the User table)
entityManager.flush();