3

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.

henriqueor
  • 849
  • 1
  • 17
  • 38
  • Found similar question here, hope it helps https://stackoverflow.com/questions/3194721/bypass-generatedvalue-in-hibernate-merge-data-not-in-db – vamsikurre Mar 20 '19 at 04:42

2 Answers2

4

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.

henriqueor
  • 849
  • 1
  • 17
  • 38
1

Simply remove the @GeneratedValue annotation

 @Id
 @Column(name = "id_usuario", unique = true, nullable = false)
 private int id;
msp
  • 3,272
  • 7
  • 37
  • 49
  • 2
    I can't remove the sequence generator, because it is used in many other parts on the system. The question I asked is for some specific features, where the ID is given by the central server. – henriqueor Mar 20 '19 at 17:04
  • 1
    Ok, including that you need both auto generated *and* IDs from the central server would have been a value piece of information in your question. – msp Mar 22 '19 at 10:01