10
public class SequenceControlNumber extends SequenceGenerator {

    private static final Logger log =
        LoggerFactory.getLogger(SequenceGenerator.class);

    @Override
    public Serializable generate(SessionImplementor session, Object obj) {
        Connection connection = session.connection();
        try {
            PreparedStatement st = connection.prepareStatement
                   ("SELECT nextval ('sequencecontrolnumber') as nextval");
            try {
                ResultSet rs = st.executeQuery();
                try {
                    rs.next();
                    int currentVall = rs.getInt("sequencecontrolnumber");
                    int result = 0;
                    if(currentVall <255){
                        result = currentVall +1;
                    }
                    if ( log.isDebugEnabled() ) {
                        log.debug("Sequence identifier generated: " + result);
                    }
                    return result;
                }
                finally {
                    rs.close();
                }
            }
            finally {
                session.getBatcher().closeStatement(st);
            }
        }
        catch (SQLException sqle) {
            throw JDBCExceptionHelper.convert(
                    session.getFactory().getSQLExceptionConverter(),
                    sqle,"could not get next sequence value");
        }
    }

}

In my model class this is my annotation:

@GenericGenerator(name="seq_id",
        strategy="br.com.otgmobile.service.dao.SequenceControlNumber")
@GeneratedValue(generator="seq_id")
@Column(name="sequencecontrolnumber",unique=false, nullable=false)
private Integer sequenceControlNumber;

but I keep getting a a property value exception.

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.otgmobile.model.niagarahw06.ComandoNiagaraHw06.sequenceControlNumber
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1179)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1112)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1118)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:618)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy33.persist(Unknown Source)
at br.com.otgmobile.service.dao.ComandoNiagaraHw06DAO.add(ComandoNiagaraHw06DAO.java:57)
at br.com.otgmobile.service.dao.ComandoNiagaraHw06DAO$$FastClassByCGLIB$$e19cf51d.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at br.com.otgmobile.service.dao.ComandoNiagaraHw06DAO$$EnhancerByCGLIB$$69ccb4e4.add(<generated>)
at br.com.otgmobile.server.NiagaraSocketManager.testPersistComandos(NiagaraSocketManager.java:100)
at br.com.otgmobile.server.NiagaraSocketManager.start(NiagaraSocketManager.java:45)
at br.com.otgmobile.server.NiagaraDaemon.run(NiagaraDaemon.java:25)
at java.lang.Thread.run(Thread.java:722)

Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.otgmobile.model.niagarahw06.ComandoNiagaraHw06.sequenceControlNumber
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:101)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:800)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:774)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:778)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:612)
Stephan
  • 41,764
  • 65
  • 238
  • 329
B. TIger
  • 459
  • 3
  • 10
  • 27

5 Answers5

6

For custom sequence generator for a non id field you can use @GeneratorType with ValueGenerator class implementation. For example:

  1. Entity:
    import org.hibernate.annotations.GeneratorType

    @GeneratorType(type = CustomGenerator.class, when = GenerationTime.INSERT)
    @Column(name = "CUSTOM_COLUMN", unique = true, nullable = false, updatable = false, lenght = 64)
    private String custom;
  1. ValueGenerator implementation:
public class CustomGenerator extends ValueGenerator<String> {
        private static final String TODAY_EXAMPLE_QUERY = "from Example where createDate>:start and createDate<:end order by createDate desc";
        private static final String START_PARAMETER = "start";
        private static final String END_PARAMETER = "end";
        private static final String NEXTVAL_QUERY = "select EXAMPLE_SEQ.nextval from dual";
        private final SimpleDateFormat dataFormat = new SimpleDateFormat("yyyyMMdd");

        @Override
        public String generateValue(Session session, Object owner) {
            Date now = new Date();
            Query<Example> todayQuery = session.createQuery(TODAY_EXAMPLE_QUERY, Example.class);
            todayQuery.setParameter(START_PARAMETER, start(now));
            todayQuery.setParameter(END_PARAMETER, end(now));
            Example todayLastExample = todayQuery.setMaxResult(1).setHibernateFlushMode(COMMIT).uniqueResult();

            NativeQuery nextvalQuery = session.createSQLQuery(NEXTVAL_QUERY);
            Number nextvalValue = nextvalQuery.setFlushMode(COMMIT).uniqueResult();
            return dataFormat.format(now) + someParameter(todayLastExample) + nextvalValue.longValue();
        }
    }
Mirimas
  • 735
  • 10
  • 15
5

This works for me in Postgres at least

@Generated(GenerationTime.INSERT)
@Column(name = "internal_id", columnDefinition = "serial", updatable = false)
private int internalId;
Aritra Das
  • 262
  • 3
  • 8
  • After a few hours of searching trying everything suggested, this is the only thing that worked for me using Postgres. Thank you Aritra, Thank you! – eugene Feb 17 '22 at 00:31
  • @Aritra Das what is the package name of GenerationTime.INSERT i didn't found any suggestion ? thanks – James Jun 23 '22 at 09:30
  • @James It is org.hibernate.annotations.Generated and org.hibernate.annotations.GenerationTime. – OJVM Sep 01 '23 at 18:23
2

The @GeneratedValue annotation is not something that Hibernate will process as part of a column's information. It has to be used in conjunction with the @Id annotation. It just says how the id is generated when there is an id.

You have a few options to accomplish what you want, but none of them are really as elegant as just using an annotation like you've written. These suggestions have their pros and cons (database portability, complexity, entity manager vs. session, etc.) but some ideas are:

  • Implement a PreInsertListener and add it to your AnnotationConfiguration. This listener would look for the type of entity that needed this functionality and would get/assign the next sequence value
  • Make a database trigger to handle populating the column with a sequence value. Mark the column in your Java code as insertable = false, updatable = false
  • Put your generate logic into a callback method in your entity and mark it with a @PrePersist annotation
  • Populate the field as part of the constructor (not preferred since then you have a DB call in a constructor and some potential transaction boundary ambiguity)
Jeff
  • 3,669
  • 1
  • 23
  • 33
1

Check the value of result returned from the generate method in SequenceControlNumberclass.

BTW check this response in this SO question : Hibernate JPA Sequence (non-Id)

Community
  • 1
  • 1
Stephan
  • 41,764
  • 65
  • 238
  • 329
  • Thanks man but that just removed the exception and showed me the real problem that the seuqnce is not beeing generated because now all my values are 0 on that field – B. TIger Sep 19 '12 at 14:06
  • I've put it on debug mode but when I persist the it the debugger does not go there, I trying to see if there is a problem with my annotation – B. TIger Sep 19 '12 at 14:25
1

I just faced a similar issue where I needed to create and attach a sequence to a field which is not a primary key.

I was struggling trying to use @GeneratedValue and @SequenceGenerator annotations, because as stated on the Web : @GeneratedValue can only be used along an @Id annotation on an Hibernate entity field. This, tells Hibernate not to care about the field being null, it will be managed at insertion time into the database. But here Hibernate was always throwing Exception because the GeneratedValue was ignored on the field.

So the solution is simple : Just replace this annotation by @Generated(GenerationTime.INSERT) and add columnDefinition = "serial" into your @Column(name = "huhu", columnDefinition = "serial", updatable = false, ...)

Normally it should now work, if you have created the correct sequence attached to the field in the database in the first place.

Alex
  • 4,599
  • 4
  • 22
  • 42