JPA or Hibernate to generate a (non primary key) column value, not starting from 1

前端 未结 3 1170
别跟我提以往
别跟我提以往 2021-01-06 06:10

I want a JPA/Hibernate (preferably JPA) annotation that can generate the value of a column, that is not a primary key and it doesn\'t start from 1.

From what I have

相关标签:
3条回答
  • 2021-01-06 06:46

    Here's what worked for me - we coded all of it in the service. Here's the entity:

    @Entity
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    public class Registrant extends AbstractEntity {
        //....
        private long invoiceNumber;//invoice number
    
        @Entity
        public static class InvoiceNumberGenerator {
            @Id
            @GeneratedValue
            private int id;
            private long counter;
    
            public int getId() {
                return id;
            }
    
            public void setId(int id) {
                this.id = id;
            }
    
            public long getCounter() {
                return counter;
            }
    
            public void setCounter(long counter) {
                this.counter = counter;
            }
        }
    }
    

    And then we have a service that does the magic (actually there's no magic, all is done manually):

    public synchronized Registrant save(Registrant registrant) {
        long counter = getInvoiceNumber();
        registrant.setInvoiceNumber(counter);
    
        return registrantRepository.save(registrant);
    }
    
    private long getInvoiceNumber() {
        //mist: get the invoice number from the other table
        long count = registrantInvoiceNumberGeneratorRepository.count();
        if(count > 1) {
            throw new RuntimeException(": InvoiceNumberGenerator table has more than one row. Fix that");
        }
    
        Registrant.InvoiceNumberGenerator generator;
        if(count == 0) {
            generator = new Registrant.InvoiceNumberGenerator();
            generator.setCounter(1000001);
            generator = registrantInvoiceNumberGeneratorRepository.save(generator);
        } else {
            generator = registrantInvoiceNumberGeneratorRepository.findFirstByOrderByIdAsc();
        }
    
    
        long counter = generator.getCounter();
        generator.setCounter(counter+1);
        registrantInvoiceNumberGeneratorRepository.save(generator);
        return counter;
    }
    

    Note the synchronized method - so that nobody can get the same number.

    I can't believe there's nothing automatic that can do that.

    0 讨论(0)
  • 2021-01-06 06:59

    The @GeneratedValue only works for identifiers and so you can't use it. If you use MySQL, you are quite limited, since database sequences are not supported.

    InnoDB doesn't support multiple AUTO_INCREMENT columns and if your table PK is AUTO_INCREMENTED, then you have two options:

    1. Go for a separate table that behaves like a sequence generator, the solution you already said you are not happy about.

    2. Use an INSERT TRIGGER to increment that column.

    0 讨论(0)
  • 2021-01-06 07:03

    Related to @Vlad Mihalcea, now you can use @GeneratorType to generate your own custom value for non id column. 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();
            }
        }
    
    0 讨论(0)
提交回复
热议问题