How to use a sequence generator for a non ID field?

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)

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);
            query.setParameter(START_PARAMETER, start(now));
            query.setParameter(END_PARAMETER, end(now));
            Example lastExample = todayQuery.setMaxResult(1).setHibernateFlushMode(COMMIT).uniqueResult();

            NativeQuery nextvalQuery = session.createSQLQuery(NEXTVAL_QUERY);
            Number nextvalValue = nextvalQuery.setFlushMode(COMMIT).uniqueResult();
            return dataFormat.format(now) + someParameter(lastExample) + nextvalValue.longValue();
        }
    }

Tags:

Java

Hibernate