如何用Hibernate实现一个自定义的String序列标识符生成器 [英] How to implement a custom String sequence identifier generator with Hibernate

查看:236
本文介绍了如何用Hibernate实现一个自定义的String序列标识符生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在spring中使用hibernate,h2和liquibase,我试图通过以博文但是我得到一个错误:引起:org.hibernate.id.IdentifierGenerationException:ids的未知整数数据类型:java.lang.String



这里是我的SequenceStyleGenerator代码:

  public class CTCIDGenerator extends SequenceStyleGenerator {

@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;
}
}
返回CTC+ super.generate(session,obj);


$ / code>

我的实体代码:

  @Entity 
@Table(name =contact)
public class Contact实现Serializable,Identifiable< String> {

private static final long serialVersionUID = 1L;

@Id
@GenericGenerator(
name =assigned-sequence,
strategy =net.atos.seirich.support.domain.idgenerator.CTCIDGenerator ,
parameters = @ org.hibernate.annotations.Parameter(
name =sequence_name,
value =hibernate_sequence


@ GeneratedValue(generator =assigned-sequence,strategy = GenerationType.SEQUENCE)
private String id;

public String getId(){
return id;
}

public void setId(String id){
this.id = id;




  • 和liquibase XML:

     <?xml version =1.0encoding =utf-8?> 
    < databaseChangeLog
    xmlns =http://www.liquibase.org/xml/ns/dbchangelog
    xmlns:xsi =http://www.w3.org/2001 / XMLSchema-instance
    xsi:schemaLocation =http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd >



    < changeSet id =20160513091901-1author =jhipster>
    < createTable tableName =contact>
    < column name =idtype =longvarcharautoIncrement =$ {autoIncrement}>
    < constraints primaryKey =truenullable =false/>
    < / column>
    < / changeSet>
    < / databaseChangeLog>

    顺便说一句,有可能避免参数sequence_name,因此hibernate可以自己处理这个参数吗?



    如果有人可以帮助我,谢谢!

    解决方案

    问题在于 SequenceStyleGenerator 期望返回一个数值,而不是 String



    我已经尝试 a这个问题的解决方案,它像一个魅力。因此,您需要更改您的生成器,如下所示:

      public class StringSequenceIdentifier implements IdentifierGenerator,Configurable {

    private String sequenceCallSyntax;
    $ b @Override
    public void configure(Type params,ServiceRegistry serviceRegistry)throws MappingException {
    final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService(JdbcEnvironment.class);
    final方言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));

    $ b @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 );

    返回CTC+ seqValue;


    $ / code $ / pre
    $ b $ p您的映射变为:

      @Entity(name =Post)
    @Table(name =post)
    public static class Post implements Identifiable<串GT; {

    @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)
    私人字符串ID;

    @版本
    私人整数版本;
    $ b $ public Post(){
    }

    public Post(String id){
    this.id = id;
    }

    @Override
    public String getId(){
    return id;


    现在,当您插入以下实体时: p>

      doInJPA(entityManager  - > {
    entityManager.persist(new Post());
    entityManager.persist (new Post(ABC));
    entityManager.persist(new Post());
    entityManager.persist(new Post(DEF));
    });

    Hibernate生成正确的标识符:

     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 ,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)]

    GitHub


    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 getting an error : Caused by: org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String

    Here my SequenceStyleGenerator code :

    public class CTCIDGenerator extends SequenceStyleGenerator {
    
        @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;
                }
            }
            return "CTC"+super.generate(session, obj);
        }
    }
    

    My entity code :

    @Entity
    @Table(name = "contact")
    public class Contact implements Serializable, Identifiable<String> {
    
        private static final long serialVersionUID = 1L;
    
        @Id
        @GenericGenerator(
            name = "assigned-sequence",
            strategy =     "net.atos.seirich.support.domain.idgenerator.CTCIDGenerator",
            parameters = @org.hibernate.annotations.Parameter(
                name = "sequence_name", 
                value = "hibernate_sequence"
            )
        )
        @GeneratedValue(generator = "assigned-sequence", strategy = GenerationType.SEQUENCE)
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    

    And the liquibase XML :

    <?xml version="1.0" encoding="utf-8"?>
    <databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
    
        <property name="autoIncrement" value="true" dbms="mysql,h2,postgresql,oracle"/>
    
        <property name="floatType" value="float4" dbms="postgresql, h2"/>
        <property name="floatType" value="float" dbms="mysql, oracle"/>
    
        <changeSet id="20160513091901-1" author="jhipster">
            <createTable tableName="contact">
                <column name="id" type="longvarchar" autoIncrement="${autoIncrement}">
                    <constraints primaryKey="true" nullable="false"/>
                </column>
        </changeSet>
    </databaseChangeLog>
    

    Btw is it possible to avoid the parameter sequence_name so hibernate can handle this by itself ?

    If anyone can help me, Thanks !

    解决方案

    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.

    这篇关于如何用Hibernate实现一个自定义的String序列标识符生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆