JPA ID生成策略

时间:2011-02-22 18:00:05

标签: java hibernate jpa

我为JPA类定义了一个生成器:

<sequence-generator name="MY_SEQ" allocation-size="-1"
    sequence-name="MY_SEQ"
    initial-value="100000000" />

在某些情况下,我已经拥有实体的ID,但是当我插入实体时,ID会使用生成器生成。

是否可以定义一个只在不存在时生成Id的生成器?

我正在使用Hibernate作为JPA Provider。

谢谢

2 个答案:

答案 0 :(得分:1)

我在JPA中找不到这样做的方法所以我使用了Hibernate EJB3事件监听器。我过度使用saveWithGeneratedId来使用反射来检查实体是否有@Id注释,然后检查该字段是否有值。如果它有值,那么我会调用saveWithRequestedId。其他明智的我让它生成Id。这很有效,因为如果我需要Id,我仍然可以使用设置的Hibernate序列。反射可能会增加开销,所以我可能会稍微改变一下。我想在所有实体中使用getId()getPK()方法,因此我不必搜索哪个字段是@Id

在我使用反射之前,我尝试调用session.getIdentifier(entity)来检查但是我得到了TransientObjectException(“实例未与此会话相关联”)。我无法弄清楚如何让实体进入会话而不先保存它,所以我放弃了。下面是我写的听众代码。

public class MergeListener extends org.hibernate.ejb.event.EJB3MergeEventListener
 {



    @Override
    protected Serializable saveWithGeneratedId(Object entity, String entityName, Object anything, EventSource source, boolean requiresImmediateIdAccess) {


        Integer id = null;


            Field[] declaredFields = entity.getClass().getDeclaredFields();

            for (Field field : declaredFields) {

                Id annotation = field.getAnnotation(javax.persistence.Id.class);

                if(annotation!=null) {


                    try {
                        Method method = entity.getClass().getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
                        Object invoke = method.invoke(entity);

                       id = (Integer)invoke;


                    } catch (Exception ex) {
                      //something failed (method not found..etc) , keep going anyway
                    }

                    break;

                }
            }



       if(id == null ||
                id == 0) {
        return super.saveWithGeneratedId(entity, entityName, anything, source, requiresImmediateIdAccess);
        } else {

            return super.saveWithRequestedId(entity, id, entityName, anything, source);
        }
    }
}

然后我必须将监听器添加到我的persistence.xml

 <property name="hibernate.ejb.event.merge" value="my.package.MergeListener"/>

答案 1 :(得分:0)

这不是一个好主意,序列用于代理键,在商业意义上没有意义,但向你保证,不会有重复,因此在插入时没有错误。