I have a table with a generated id, but in some cases I would like to set it on my own. Can I, somehow, force Hibernate to ignore the @GeneratedValue?
It may be an overkill but have you thought about writing your own CustomIDGenerator which probably subclasses say the AutoGenerator of hibernate and exposes a couple of methods where you can set the id of the next class object to be generated so for example
class MyGenerator extends .... {
public void setIdForObject(Class clazz, Long id) {
//once you use this API, the next time an object of
//type clazz is saved the id is used
}
public void setIdForObject(Class clazz, Long id, Matcher matcher) {
//once you use this API, the next time an object of
//type clazz is saved and the matcher matches yes the id will be
//assigned. Your matcher can match properties like name, age etc
//to say the matched object
}
}
This could get complicated but at the least is possible as per hibernate doco
shouldAlwaysOverrideExistingValue
which can be overridden. This seems to be a possible solution. Although it feels a little uncomfortable to override things I do not completely oversee and also didn't find any documentation to other than this bug entry. –
Grackle create your own identifiergenerator/sequencegenerator
public class FilterIdentifierGenerator extends IdentityGenerator implements IdentifierGenerator{
@Override
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
// TODO Auto-generated method stub
Serializable id = session.getEntityPersister(null, object)
.getClassMetadata().getIdentifier(object, session);
return id != null ? id : super.generate(session, object);
}
}
modify your entity as:
@Id
@GeneratedValue(generator="myGenerator")
@GenericGenerator(name="myGenerator", strategy="package.FilterIdentifierGenerator")
@Column(unique=true, nullable=false)
private int id;
...
and while saving instead of using persist()
use merge()
or update()
Although this question was asked quite a while ago, I found the perfect answer for it in this post by @lOranger, and wanted to share it.
This proposal checks if the object's current id is set to something other than null
, and if so, it uses it, otherwise, it generates it using the default (or configured) generation strategy.
It's simple, straight forward, and addresses the issue brought up by @Jens, of one not being able to retrieve the object's current id.
I just implemented it (by extending the UUIDGenerator), and it works like a charm :-D
For you use case, you can manually add this no user. One way to do it is to put the insert operation on a file named "./import.sql" (in your classpath). Hibernate will go execute these statements when the SessionFactory is started.
@rakesh's solution doesn't work since hibernate 6.2 https://discourse.hibernate.org/t/hybrid-id-generation-in-hibernate-6-2-is-difficult/7666
I found a solution for hibernate 6.4.4.Final
public class AssignedOrIdentityGenerator extends IdentityGenerator implements BeforeExecutionGenerator {
@Override
public Object generate(SharedSessionContractImplementor session, Object entity, Object currentValue, EventType eventType) {
return getId(entity, session);
}
private static Object getId(Object entity, SharedSessionContractImplementor session) {
return session.getEntityPersister(null, entity)
.getIdentifier(entity, session);
}
/**
* @implNote Method {@link #generate(SharedSessionContractImplementor, Object, Object, EventType)}
* is called if this method returns false
*/
@Override
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
Object id = getId(entity, session);
return isNull(id);
}
@Override
public boolean generatedOnExecution() {
// This method is called to configure a context (using this Generator) without knowledge of a specific Entity.
// The choice for the real Entity must be made in the this.generatedOnExecution(entity, session) method.
// For example, find out comment "support mixed-timing generators" in IdentifierGeneratorUtil.class (hibernate-core):
// true is required, if ID sometimes should be generated by RDBMS (for example by AUTO_INCREMENT)
return true;
}
}
This class completly replaces @rakesh's FilterIdentifierGenerator
, the rest of the code can remain the same. This class works for AUTO_INCREMENT / IDENTITY
db columns.
If you want use TABLE
, SEQUENCE
, UUID
id generation types you can use class I've described here. Then you can wrap required "before" and "on" sql statement execution id generator implementations
class AssignedOrIdentityGenerator extends BeforeOrOnExecutionGenerator {
public AssignedOrIdentityGenerator() {
super(new Assigned(), new IdentityGenerator());
}
}
With hibernate 6.4.4 you can also create simple annotation
@Retention(RUNTIME)
@Target({METHOD, FIELD})
@IdGeneratorType(AssignedOrIdentityGenerator.class)
public @interface AssignedOrGeneratedValue {
}
So you can replace this code snippet
@Id
@GeneratedValue(generator = "assigned-or-generated")
@GenericGenerator(name = "assigned-or-generated", type = AssignedOrIdentityGenerator.class)
@Column(name = "id")
private Integer id;
with a simpler one
@Id
@AssignedOrGeneratedValue
@Column(name = "id")
private Integer id;
© 2022 - 2024 — McMap. All rights reserved.
merge()
rather thanpersist()
– Apocrypha