I want to implement one auto increment field other than id field that starts with 1 and increase by 1 sequentially.
Code Sample :
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
private String id; //Id primary key
#Column(name = "request_number", nullable = false, unique = true, updatable = false, insertable = false)
#GeneratedValue(generator = "sequence", strategy = GenerationType.AUTO)
private Long requestNumber; //Talking about this
So, here requestNumber should increase automatically every time when ever object create. And that should increase sequentially.
Example : First entry's requestNumber will start with 1 and next requestNumber will be assign with 2 and so on...
I know it is possible via java code but I am looking for JPA provide such flexibility.
#GeneratedValue is used only for simple primary keys, as per the javadoc:
The GeneratedValue annotation may be applied to a primary key property or field of an entity or mapped superclass in conjunction with the Id annotation. The use of the GeneratedValue annotation is only required to be supported for simple primary keys. Use of the GeneratedValue annotation is not supported for derived primary keys.
If you want to do it in JPA you can define a #PrePersist method like:
#PrePersist
void doPrePersist() {
// Use EntityManager to create a native query
// read next value from a sequence
// set the field value
}
Another option would be to define the database column as IDENTITY but this will take care of auto incrementing outside of JPA e.g. the entity field won't be insertable and value won't be seen during entity persist operation.
Please note that SQL Server, and most databases, doesn't guarantee that there won't be gaps in the sequence. When a transaction that increments sequence is rolled back the value of the sequence is not, so you can end up with: 1, 2, 4, 5, 6, 10, ...
You have to declare a #SequenceGenerator annotation on your class (or field):
#SequenceGenerator(sequenceName = "MY_DB_SEQUENCE", name = "sequence")
public class MyClass {
// keep as is
}
Note that the generator = "sequence" on #GeneratedValue points to the #SequenceGenerator with the name = "sequence"
Related
I have a situation in which I find the next sequence value (using nextval), set it to a database column and I want to reuse that value as the object's primary key. The problem is that although I triggger save with the correct values, Spring JPA generates another primary key and does not use the one I gave it.
For example, I have an entity:
public class MyEntity implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_MY_ENTITY")
#SequenceGenerator(sequenceName = "SEQ_MY_ENTITY", allocationSize = 1, name = "SEQ_MY_ENTITY")
private Long id;
#Column(name = "field1")
private String field1;
In some business flow, I need to set field1 = id. I do this by:
get next val from dual.
set value to field1
set value to id
Problem is that what is saved for id = field1 + 1. How can I have the two values in sync without calling save with empty field1 and then another save after I've updated field1?
You can use #Id on two columns : id and field1 or use composite key using #Embeddable
There is already some data available in table, where id being the primary key for me. So when i trying to invoke my spring jpa code to add values to the table i'm using #GeneratedValue for the primary key.
But this way is generating value which is already present in DB. so my application is throwing an exception.
Is there any way i can get the current value from the table and increment my primary key id wrt the previous value of ID present in the table
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id", updatable = false, nullable = false)
private int id;
Let's say your max id in DB currently is 500. Run this:
CREATE SEQUENCE seq_name_in_db START WITH 501;
And change to:
#Id
#SequenceGenerator(name = "some_seq", sequenceName = "seq_name_in_db")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "some_seq")
private int id;
UPDATE: (Solution to OP's comment)
While inserting directly, do this:
INSERT INTO some_table (id, ...) VALUES (seq_name_in_db.NEXTVAL, ...);
When You create the sequence, you can let it start with a certain value e.g.
CREATE SEQUENCE XX_SEQ
START WITH 100
INCREMENT BY 1 ;
I added a sequence MAIL_ID_SEQ to an existing table in Postgresql :
CREATE SEQUENCE MAIL_ID_SEQ START WITH 1;
alter table MAIL alter column ID set default nextval('MAIL_ID_SEQ'::regclass);
alter SEQUENCE MAIL_ID_SEQ owned by MAIL.ID;
The ID exist inside a composite key MailId :
#Embeddable
public class MailId implements Serializable{
#Column(name = "ID")
private int id;
#Column(name = "YEAR")
private int year;
}
I want the ID to be auto_increment using the sequence I created.
The problem is that the value of the ID is always 0 when a new record is inserted from via Hibernate, but when I insert a value directly from the command line (inset into MAIL ..) in the MAIL table, the value of the ID is incremented.
You need to add annotations like this to the id field:
#SequenceGenerator(name = "mail_id_gen", sequenceName = "MAIL_ID_SEQ", allocationSize = 1)
#GeneratedValue(generator = "mail_id_gen")
The generator name must be different for each class. The allocationSize is completely optional, but setting it to 1 is a workaround to a bug in Hibernate 5.0 and 5.1 related to sequences not created by schema export. Another workaround for that bug is to set the hibernate.id.optimizer.pooled.preferred property to NONE in the persistence.xml like this:
<property name="hibernate.id.optimizer.pooled.preferred" value="NONE"/>
If this is not enough and it still tries to insert 0, change the field type from int to Integer and leave it's default to null.
I'm in a project which is based on Oracle DB and EclipseLink as EM implementation.
I got a table which has a standard id sequence generator, let's say:
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "INVOICE")
#TableGenerator(name = "INVOICE", allocationSize = 1, table = Constants.SEQUENCE_TABLE, schema = Constants.DATABASE_SCHEMA)
#Column(length = 40)
private String id;
I also got a unique numeric field. I've decided to create a special sequence for that field, and populate it through a trigger, which increments that numeric field on every insert, passing sequence "NextVal".
My question is: is it a good practice to take advantage of #Sequencegenerator and #TableGenerator annotation also for a field that is not an #Id for the same entity?
I'm not a trigger fan...so adding a thing like this from the hypothetical first snippet... i could manage whole entity with JPA standard Annotations:
#GeneratedValue(strategy = GenerationType.TABLE, generator = "UNIQUEFIELD")
#TableGenerator(name = "UNIQUEFIELD", allocationSize = 1)
#Column
private String uniqueValuesField;
Thanks!
JPA does not support sequences on non-id fields, so this isn't likely to work without relying or delving into your provider's native support.
You can always refresh the entity afterward if required to get the values set by triggers, but they are a common enough occurrence on legacy systems, so providers will have support of some form for triggers. EclipseLink has #ReturnInsert and #ReturnUpdate to allow getting the values back from triggers.
To mark a property as generated, use The Hibernate specific #Generated annotation.Properties marked as generated must additionally be non-insertable and non-updateable. Only #Version and #Basic types can be marked as generated.
http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#mapping-generated
never (the default)
the given property value is not generated within the database.
insert
the given property value is generated on insert, but is not regenerated on subsequent updates. Properties like creationTimestamp fall into this category.
always
the property value is generated both on insert and on update.
hope this can help you.
I think writing a trigger is a redundant action, and it will reduce the readability of the code.
There are three main types of ID generators provided in hibernate TABLE, SEQUENCE and IDENTITY.
here is a good read with examples by Vladmihalcea on the Sequence generator strategies provided.
Or else you can create your own sequence generator where I had to keep a unique id among two tables so I did this
#Id
#GenericGenerator(name = "sequence", strategy = "IdGenerator")
#GeneratedValue(generator = "sequence")
#Column(name = "ID", columnDefinition = "BIGINT")
and in the Id generator
Public class IdGenerator extends IncrementGenerator {
private static long nextVal = Long.MIN_VALUE;
private static Object idlock = new Object();
private static volatile String COLUMN_NAME = "id";
#Override
public Serializable generate(SessionImplementor session, Object obj) {
if (obj == null) {
throw new HibernateException("Null object passed");
}
synchronized (idlock) {
nextVal = //get the value according to your logic
}
return nextVal;
}
}
I have trying to insert a record into the database (MySQL), using Entity Class and Entity Manager. But one of the field is an auto incrementing primary key, so unless I provide an value manually, the insertion is not successful.
public boolean newContributor(String name, String email, String country, Integer contactable, String address) {
Contributors contributor = new Contributors(); //entity class
contributor.setId(??????); //this is Primary Key field and is of int datatype
contributor.setName(name);
contributor.setEmail(email);
contributor.setCountry(country);
contributor.setContactable(contactable);
contributor.setAddress(address);
em.persist(contributor);
return true;
}
How to solve such problem? Is there a way to tell the entity manager to attempt the insert without the ID field and use NULL value instead.
Update: Here is a portion of the entity class defining the id
...
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
....
Is there a way to tell the entity manager to attempt the insert without the ID field and use NULL value instead?
Sure. You need to remove the #NotNull annotation for id field in the #Entity definition, and also remove the row:
contributor.setId(??????);
from method newContributor(). The reason for this is that the #NotNull annotation enforces a validation check in the JPA stack. It doesn't mean that the field is NOT NULL at a database level. See here a discussion about this issue.
The rest of the code looks fine.