简体   繁体   中英

JPA Hibernate - Insert with given ID, not with sequence

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?

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.

Simply remove the @GeneratedValue annotation

 @Id
 @Column(name = "id_usuario", unique = true, nullable = false)
 private int id;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM