Problems with #GeneratedValue in the H2 database - java

Hello StackOverflow Community, I have a problem with the annotation #GenerateValue. I want that JPA generates the values for my ID column. But I have another column where people can write some sort of tasks (todo list).
My code seems like this:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
and I have a SQL data file that write some data at the beginning in my h2 database:
INSERT INTO task VALUES(1, 'go to the gym');
INSERT INTO task VALUES(2, 'eat with tom');
INSERT INTO task VALUES(3, 'meetup');
INSERT INTO task VALUES(4, 'doing some homeworks');
INSERT INTO task VALUES(5, 'doing some exercise');
INSERT INTO task VALUES(6, 'studying with Mat');
my problem is, when I delete the integer values on my SQL data file, my compiler says always that I have to declare an id for the tasks, but I thought the #GenerateValue automatically generate the id's for me?

You have to use #GeneratedValue(strategy = GenerationType.IDENTITY) or #GeneratedValue(strategy = GenerationType.SEQUENCE) and make sure that you have index or sequence on database level. Also when using auto-generated ids, don't specify them explicitly when inserting.
Correct:
INSERT INTO task(description) VALUES('go to the gym');
but I thought the "#GenerateValue" automatically generate the id's for me?
It's a not the correct assumption, Hibernate just uses ids provided by db. To get it to work you need to create index/sequence for your primary key column.

You're mixing up sql and hibernate. #GeneratedValue is declared in your java code, so that hibernate knows, that when you're persisting an entity without an id, it should be generated by given strategy.
On the other hand you tried to make insertions using sql without passing primary key, so you're explicitly said, that it should be NULL, which is clearly against the constraint.

Related

Sequence "HIBERNATE_SEQUENCE" not found for h2 test with GenerationType.AUTO

I am trying to migrate one of our services to Spring Boot 2.0.3.
While most of the tests are fine, one of them fails with error:
Caused by: org.h2.jdbc.JdbcSQLException: Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:
call next value for hibernate_sequence [90036-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.command.Parser.readSequence(Parser.java:5970)
at org.h2.command.Parser.readTerm(Parser.java:3131)
at org.h2.command.Parser.readFactor(Parser.java:2587)
This is really confusing because all teh entities rely on the same generation id mechanism:
#GeneratedValue(strategy = GenerationType.AUTO)
It's a repository test and the repository itself is very straight-forward:
#Repository
public interface OrderDetailsRepository extends JpaRepository<OrderDetails, Long> {
OrderDetails findFirstByOrderIdOrderByIdDesc(String orderId);
}
What can possible go wrong here?
PS: And, yes, there is both orderId and Id field present in the entity.
When you choose #GeneratedValue(strategy = GenerationType.AUTO) Hibernate selects a generation strategy based on the database-specific dialect.
The problem in your case is hibernate can't find the HIBERNATE_SEQUENCE and thus can't create a new object for the sequence. Try adding a sequence like this and it should solve the problem, but could lead to inconsistencies with the data...
CREATE TABLE CUSTOMER(
  id int primary key,
);
CREATE SEQUENCE HIBERNATE_SEQUENCE START WITH 1 INCREMENT BY 1;
I would suggest using the GenerationType.SEQUENCEand try to recreate your id pattern with your custom db sequence. You can read more about the GenerationType's
here
I encountered the same issue when written sample code for spring boot with h2. please find the details below of my findings.
In your entity class sequence is not given and check your table as well i.e. have you given AUTO_INCREMENT for primary key?
Please follow as below.
1. Check your ddl once and set auto_increment for primary key (see below for id)
CREATE TABLE EMPLOYEES (
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(250),
last_name VARCHAR(250),
email VARCHAR(250) DEFAULT NULL
);
Check your entity class and update primary key as below
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Please make a note that GenerationType is given IDENTITY you can give AUTO as well. Also if you are using h2 in-memory DB and table inserted few records while boot-start (if dml file available in resource) then hibernate insertion may give unique constraint because sequence 1,2,3..(depends on how many records inserted while startup) may have already used and as I said above hibernate will generate the sequence from 1 and will increment by 1 for every new insertion. So I would suggest don't insert records while boot startup better to insert programmatically.
For your learning you can use as given above but if it may use in production then better to implement your own logic to generate the sequence.
I had similar problem. If I understand things correctly It went down like this.
Before Spring upgrade I used AUTO - but it actually opted by default to IDENTITY strategy. I had auto incrementing PKs defined like this:
id BIGINT AUTO_INCREMENT PRIMARY KEY
Everything was fine.
With spring upgrade I had to specify H2 dialect:
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
I've read that if you use Hibernate as your persistence provider, it selects a generation strategy based on the database specific dialect. For H2 it probably opted for global sequence (that's what AUTO should mean according to JPA spec) - and it didn't find the sequence.
Solution is of course create the sequence (as suggested above) or manually override to originally auto selected IDENTITY.
CREATE SEQUENCE HIBERNATE_SEQUENCE START WITH 1 INCREMENT BY 1;
#GeneratedValue(strategy = GenerationType.IDENTITY)
I believe that root cause is that meaning of AUTO is/was not consistent/well defined/understood in time. Probably original 'auto' switch to IDENTITY was basically a bug.

Dynamic values for JPA id generation table using #TableGenerator

I have a Spring based application which uses JPA 2.1 for the persistence layer.
I use #TableGenerator and #GeneratedValue annotations to handle my primary key id generation.
These are the annotations:
#TableGenerator(name = "user_gen", table = "id_gen", pkColumnName = "gen_name", valueColumnName = "gen_val", allocationSize = 1)
…
#GeneratedValue(strategy = GenerationType.TABLE, generator = "user_gen")
I use this entity to insert records in my user table.
It was all working good.
Now I have a new problem. An external application needs to insert records in my user tables. This causes primary key violation at my end.
Is there any option in JPA which will make my id_gen table's gen_val value updated based on the max id of my user table?
[I could not find such a solution in my research]
Other thoughts to fix the issue are also welcome.
You might make it work with custom id generator where you would check for maximum id before each insert, but I wouldn't recommend it. In my opinion, this would be best handled on database level.
How is that application generating id's? They have to get it from somewhere, so why not why not handle id in that step. Best option would be if it can use the same id_gen mechanism for this. Several ideas:
After inserting the data, they could just call your stored procedure which would take care of synchronizing ids
They could call your stored procedure prior to insert, which would return them the id for the new row
They could call your stored procedure which would insert the data instead of them inserting it directly, and you would handle the id

Hibernate Auto Increment in SQLite

I just started learning hibernate and its looking good. I am just stuck with creating a column in a table with auto increment property. Here is how I defined my column in my class:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column (name="program_id")
protected Integer programid;
The problem here is when the sql query is created it returns an error because the query is incorrect for SQLite. Here is the generated query:
create table program (program_id integer not null auto_increment....)
You see it is written as auto_increment instead of AUTOINCREMENT (ignore case) I already tried Identity and still returns an incorrect sql query.
Is there a correct "strategy" in the annotation to approach this? or is there another setup to have the correct sql query?
Try it
#Id
#Column(name = "program_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Basic
protected Integer programid;

Error Hibernate when trying to Save

I have searched on the web before posting this here, but I'm in an important project and I don't have any more time to waste with this. Well, here's the deal:
My tables in the database(SqlServer) are created automatically by Hibernate. So, I have an Entity and this entity was mapped before with Id annotation, like this:
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int id;
Hibernate created a table dbo.Parcela inside sqlServer, but we had to change the way we generate the id, Because sometimes we receive the id number and we want that id saved on our database. So our Entity now is like this:
#Id
private Integer id;
Things work fine when we run the program for the first time, but we have some customers that already have their databases created with old Id mapping and we cannot create a new table, with the new Id mapping. So when I'm trying to insert a new record I get this message:
SEVERE: Cannot insert explicit value for identity column
in table 'Parcela' when IDENTITY_INSERT is set to OFF.
Any help would be appreciate.
Thanks
So you want your surrogate keys generated by the database, except when they were already generated by the customer. How are you going to avoid collisions, if the database wants to set id=12345, but a customer-imported entry with that id already exists?
The short answer to your question is: don't do this. I don't want to go into the old natural key vs surrogate key debate, this has been done already for example here. And google "codd surrogate keys" to learn how to properly use them. All i want to say is: if you use surrogate keys, then have your database generate them, and treat everything from outside as additional lookup key. That's the sane way.
The long answer is: if you really want to do this, and if you really know what you're doing, you can implement your own IdGenerator class. In JPA for example, you could annotate your id:
#Id
#GenericGenerator(name = "customId", strategy = "com.example.CustomIdGenerator", parameters = { #Parameter(name = "sequence", value = "SEQ_IDGENERATOR") })
#GeneratedValue(generator = "customId")
#Column(name = "ID", unique = true, nullable = false)
private Integer id;
Your customIdGenerator would then extend SequenceGenerator:
public class CustomIdGenerator extends SequenceGenerator {
public Serializable generate(SessionImplementor session, Object obj) {
// return o.getId() if obj.getId() is not null
// newId = SEQ_IDGENERATOR.nextval
// while (newId is already in db) newId = SEQ_IDGENERATOR.nextval
// return newId
}
}
and your database would provide SEQ_IDGENERATOR. Id would no longer be an autogenerated field but simply
create table foo( id integer not null primary key, ...);
But again: you don't want to do this. You want your surrogate keys to be irrelevant to the outside world and handled by the database.
How did you have Hibernate create the schema for the DB? If you used hbm2ddl perhaps adding
<property name="hibernate.hbm2ddl.auto" value="update"/>
to your persistence.xml or setting hbm2ddl.auto to "update" may have Hibernate automatically update the db schema on redeploy, having it fix the insertion problem.
Of course it won't help you in cases when you try inserting an already existing id, but i guess you know it :)

GeneratedValue in Postgres

I have my entity class mapped like below:
#Entity
#Audited
#Table(name="messages_locale")
public class Locale {
#Id
#GeneratedValue
#Getter #Setter //Project Lombok's annotations, equal to generated getter and setter method
private int id;
(...)
I create clean new database ,and properties:
< prop key="hibernate.hbm2ddl.auto" >create < /prop>
WHY THE HELL (Sorry, almost two days wasted on this bug) after created database, i got a sequence in my postgres db?:
CREATE SEQUENCE hibernate_sequence
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 2
CACHE 1;
ALTER TABLE hibernate_sequence
OWNER TO postgres;
I dont want to have a sequence, I want to have just auto increment auto generated values..
I think the accepted answer from Petar is not correct, or not correct any longer. The auto-increment in Postgres is handled through SERIAL pseudo type, that’s correct. However, the mapping that Petar gives will result in the following DDL generated by Hibernate 5.1:
CREATE SEQUENCE users_id_seq START 1 INCREMENT 50;
CREATE TABLE … (
id INT8 NOT NULL,
…
);
This is not using SERIAL, but a Hibernate managed sequence. It is not owned by the table and no default value has been set. Of course, DDL generation is a feature that many people do not use in production (but many take the generated code as a template).
If you hand-write your DDL and actually used SERIAL, then using GenerationType.SEQUENCE may even conflict with the database behaviour. The correct way to map Hibernate with Postgres’ preferred ID strategy is using GenerationType.IDENTITY. Incidentally, the code is also much shorter and more readable:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
In PostgreSQL auto-increment is handled using the SERIAL pseudo type. You use this type when you execute CREATE TABLE.
Now to the point - this SERIAL pseudo type creates a sequence.
Autoincrement in PostgreSQL is handled using the created sequence. The default value of the id column becomes - nextval('your_sequence_name').
In Hibernate for an User entity:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_seq_gen")
#SequenceGenerator(name = "users_seq_gen", sequenceName = "users_id_seq")
public Long getId() {
return id;
}
Read here:
http://www.postgresql.org/docs/8.4/static/datatype-numeric.html#DATATYPE-SERIAL
http://www.neilconway.org/docs/sequences/

Categories