How to implement a custom String sequence identifier generator with Hibernate

后端 未结 2 1987
渐次进展
渐次进展 2020-12-08 18:03

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

相关标签:
2条回答
  • 2020-12-08 18:42

    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.

    0 讨论(0)
  • 2020-12-08 18:47

    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.

    0 讨论(0)
提交回复
热议问题