I\'m using hibernate with spring, h2 and liquibase and I\'m trying to make a custom String id generator for my entities by taking example with this blog post but I\'m gettin
The problem is that SequenceStyleGenerator
expects to return a numerical value, not a String
.
I already tried a solution for this problem and it works like a charm. Therefore, you need to change your generator like this:
public class StringSequenceIdentifier implements IdentifierGenerator, Configurable {
private String sequenceCallSyntax;
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService(JdbcEnvironment.class);
final Dialect dialect = jdbcEnvironment.getDialect();
final String sequencePerEntitySuffix = ConfigurationHelper.getString(CONFIG_SEQUENCE_PER_ENTITY_SUFFIX, params, DEF_SEQUENCE_SUFFIX);
final String defaultSequenceName = ConfigurationHelper.getBoolean(CONFIG_PREFER_SEQUENCE_PER_ENTITY, params, false)
? params.getProperty(JPA_ENTITY_NAME) + sequencePerEntitySuffix
: DEF_SEQUENCE_NAME;
sequenceCallSyntax = dialect.getSequenceNextValString(ConfigurationHelper.getString(SEQUENCE_PARAM, params, defaultSequenceName));
}
@Override
public Serializable generate(SessionImplementor session, Object obj) {
if (obj instanceof Identifiable) {
Identifiable identifiable = (Identifiable) obj;
Serializable id = identifiable.getId();
if (id != null) {
return id;
}
}
long seqValue = ((Number) Session.class.cast(session)
.createSQLQuery(sequenceCallSyntax)
.uniqueResult()).longValue();
return "CTC" + seqValue;
}
}
Your mapping becomes:
@Entity(name = "Post")
@Table(name = "post")
public static class Post implements Identifiable<String> {
@Id
@GenericGenerator(
name = "assigned-sequence",
strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.StringSequenceIdentifier",
parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "hibernate_sequence")
)
@GeneratedValue(generator = "assigned-sequence", strategy = GenerationType.SEQUENCE)
private String id;
@Version
private Integer version;
public Post() {
}
public Post(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
}
Now, when you insert the following entities:
doInJPA(entityManager -> {
entityManager.persist(new Post());
entityManager.persist(new Post("ABC"));
entityManager.persist(new Post());
entityManager.persist(new Post("DEF"));
});
Hibernate generates the right identifier:
Query:["select nextval ('hibernate_sequence')"], Params:[()]
Query:["select nextval ('hibernate_sequence')"], Params:[()]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, CTC1)]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, ABC)]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, CTC2)]
Query:["insert into post (version, id) values (?, ?)"], Params:[(0, DEF)]
Code available on GitHub.
Yes, hibernate have prebuilt String generators. Just substitute your @GenericGenerator
definition to another strategy.
@Entity
@Table(name = "contact")
public class Contact implements Serializable, Identifiable<String> {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
For more information about different hibernate generators you can look at documentation.