带有Hibernate的JPA:findDirty没有考虑到新的子实体 - bug或功能?

时间:2014-12-03 16:19:23

标签: java entity-framework hibernate jpa

我们目前面临着新实体和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();

0 个答案:

没有答案