JPA ID生成策略 [英] JPA ID Generation Strategy
问题描述
我为JPA类定义了一个生成器:
< sequence-generator name =MY_SEQallocation-size = -1
sequence-name =MY_SEQ
initial-value =100000000/>
有些情况下,我已经有一个实体的ID,但是当我插入实体时,
是否有可能定义一个生成器,只有当生成器不存在时才会生成一个ID?
我使用Hibernate作为JPA Provider。
谢谢
saveWithGeneratedId
来使用反射检查 @Id
注释的实体,然后检查该字段是否为一个值。如果它有一个值,那么我调用 saveWithRequestedId
代替。其他方面,我让它生成Id。这很好,因为如果我需要一个Id,我仍然可以使用Hibernate的序列。反射可能会增加开销,所以我可能会稍微改变它。我正考虑在所有实体中使用 getId()
或 getPK()
方法,所以我不必搜索哪个字段是 @Id
。 在我使用反射之前,我尝试调用session.getIdentifier(entity)来检查,但我得到了TransientObjectException(实例没有与此会话关联)。我不知道如何让实体进入会话而不先保存它,所以我放弃了。
public class MergeListener extends org.hibernate.ejb.event.EJB3MergeEventListener
{
$覆盖
保护可序列化saveWithGeneratedId(Object entity,String entityName,Object any,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 going
}
break;
$ b if(id == null ||
id == 0){
返回super.saveWithGeneratedId(entity,entityName,anything,source,requiresImmediateIdAccess);
} else {
return super.saveWithRequestedId(entity,id,entityName,anything,source);
}
}
}
然后我必须添加监听我的persistence.xml
< property name =hibernate.ejb.event.mergevalue =my.package .MergeListener/>
I defined a generator for a JPA class:
<sequence-generator name="MY_SEQ" allocation-size="-1"
sequence-name="MY_SEQ"
initial-value="100000000" />
There are cases where I already have an ID for an entity but when I insert the Entity the Id gets generated using the generator.
Is it possible to define a generator that will only generate an Id when one does not exist?
I am using Hibernate as a JPA Provider.
Thank you
I couldn't find a way to do this in JPA so I used Hibernate EJB3 event listeners. I over rode the saveWithGeneratedId
to use reflection to check the entity for an @Id
annotation and then to check that field for a value. If it has a value then I call saveWithRequestedId
instead. Other wise I let it generate the Id. This worked well because I can still use the sequence for Hibernate that is set up if I need an Id. The reflection might add overhead so I might change it a little. I was thinking of having a getId()
or getPK()
method in all entities so I don't have to search for which field is the @Id
.
Before I used reflection I tried calling session.getIdentifier(entity) to check but I was getting TransientObjectException( "The instance was not associated with this session" ). I couldn;t figure out how to get the Entity into the session without saving it first so I gave up. Below is the listener code I wrote.
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);
}
}
}
I then had to add the listener to my persistence.xml
<property name="hibernate.ejb.event.merge" value="my.package.MergeListener"/>
这篇关于JPA ID生成策略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!