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 seen JPA cannot do that with @GeneratedValue and @SequenceGenerator and @TableGenerator. Or with anything else.
I have seen a solution with an extra table, which I find is not elegant.
I can live with a Hibernate annotation, because I already have hibernate annotations.
I want to use @Generated but I cannot make it work and people claim that it is possible.
@Generated(GenerationTime.INSERT)
private long invoiceNumber;//invoice number
Update: an extra requirement, if the transaction is rolled back, we can't have a gap in the numbering. Anyone?
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.