How to use a sequence generator for a field without an identifier?

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 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) 
+6
source share
3 answers

Check the result value returned by the generation method in the SequenceControlNumber class.

BTW checks this answer in this SO question: Sleep mode JPG sequence (not Id)

+1
source

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

You have several options to achieve what you want, but none of them are as elegant as using annotations as you wrote. These offers have their pros and cons (database portability, complexity, object manager or session, etc.), but some ideas:

  • Deploy the PreInsertListener and add it to your AnnotationConfiguration . This listener will look for the type of object that needs this function, and will get / assign the next value to the sequence
  • Make a database trigger to handle filling a column with a sequence value. Mark the column in your java code as insertable = false, updatable = false
  • Put your generation logic in a callback method in your object and mark it with @PrePersist annotation
  • Fill in the field as part of the constructor (not desirable, since then you have a DB call in the constructor and some uncertainty about the possible border of the transaction)
+1
source

I just ran into a similar problem where I needed to create and attach a sequence to a field that is not a primary key.

I struggled to use the @GeneratedValue and @SequenceGenerator annotations because, as stated on the Internet: @GeneratedValue can only be used with the @Id annotation in the Hibernate entity field. This tells Hibernate not to care about the null field, it will be managed during insertion into the database. But here, Hibernate always threw an Exception because the GeneratedValue was ignored on the field.

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

Usually this should now work if you created the correct sequence attached to the field in the database.

0
source

Source: https://habr.com/ru/post/1435058/


All Articles