Issue
I´m refactoring a system to use Spring Boot/JPA/Hibernate. There is a routine where the clients instances receive a list of objects from the central server to save. Each object from the list has an ID generated by the central server and I have to use the same ID when inserting on my clients instances, but this ID on my entity is an Autoincrement field.
My Entity:
@Entity
@Table(name = "usuario", schema = "adm")
@SequenceGenerator(name="seq_usuario_generator", sequenceName = "adm.seq_usuario", allocationSize=1)
public class UsuarioEntity implements java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_usuario_generator")
@Column(name = "id_usuario", unique = true, nullable = false)
private int id;
@Column(name = "name", length = 50)
private String name;
@Column(name = "active")
private Boolean active;
// getter and setter ommited
....
}
Should have something like this:
...
UsuarioEntity user = new UsuarioEntity();
user.setId(idFromCentralServer);
user.setName("Testing insert with given ID");
usuarioRepo.save(user);
...
When I execute this code, the given ID is ignored and a new one is generated from the local sequence.
Is there any way to save an object where I can set an ID without getting it from my sequence?
I still need to have the autoincrement feature, when the given ID is not provided.
Solution
Maybe this is not the most elegant solution I could end up with, but it solved my problem for now.
I created a custom sequence generator as follows:
public class CustomSequenceGenerator extends SequenceStyleGenerator implements Configurable {
private String sequenceCallSyntax;
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
sequenceCallSyntax = "SELECT nextval('" + params.getProperty("sequence_name") + "')";
super.configure(type, params, serviceRegistry);
}
@Override
public Serializable generate(SessionImplementor s, Object obj) {
Serializable id = s.getEntityPersister(null, obj).getClassMetadata().getIdentifier(obj, s);
if (id != null && Integer.valueOf(id.toString()) > 0) {
return id;
} else {
Integer seqValue = ((Number) Session.class.cast(s)
.createSQLQuery(sequenceCallSyntax)
.uniqueResult()).intValue();
return seqValue;
}
}
}
And my entity got like this:
@Entity
@Table(name = "usuario", schema = "adm")
@GenericGenerator(name = "CustomSequenceGenerator",
strategy = "<....my_package...>.CustomSequenceGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "adm.seq_usuario")
})
public class UsuarioEntity implements java.io.Serializable {
@Id
@GeneratedValue(generator = "CustomSequenceGenerator", strategy = GenerationType.SEQUENCE)
@Column(name = "id_usuario", unique = true, nullable = false)
private int id;
@Column(name = "name", length = 50)
private String name;
@Column(name = "active")
private Boolean active;
// getter and setter ommited
....
}
This way, when I save an entity with ID as null on my service, the generator returns the nextval from my sequence, and if I set an ID that was given by the central server it gets inserted in my table correctly.
If there is some more elegant solution, please let me know to update this answer.
Answered By - henriqueor
Answer Checked By - Robin (JavaFixing Admin)