I have the following definition for an id field in an entity that is mapped to a table in HSQLDB.
...
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "ID")
private Integer id;
...
But this does not seem to generate the an unique id; instead an attempt is made to insert null into the column which results in failure. If, I manually create a sequence and generation strategy to use that sequence then the data is persisted as expected.
Doesn't a generation strategy of auto imply that the provider (hibernate in this case) will automatically choose the correct approach and do all the heavy lifting as needed (create sequence, use a native approach or whatever works for that particular platform)? Is my understanding incorrect?
Doesn't a generation strategy of auto imply that the provider (hibernate in this case) will automatically choose the correct approach and do all the heavy lifting as needed (create sequence, use a native approach or whatever works for that particular platform)? Is my understanding incorrect?
It does in theory (it defaults to IDENTITY with HSQLDB) and it works for me. This begs the following questions:
What dialect are you using (just in case)?
How did you create the table?
Can you show the DDL (activate the logging of org.hibernate.tool.hbm2ddl if required)?
How do you insert (through Hibernate's API, right?)?
Here is a sample DDL for an entity Foo when using HSQLDB:
create table Foo (
id bigint generated by default as identity (start with 1),
bar varchar(100),
primary key (id)
)
I created the table using the HSQL DB manager. Just normal create table address... I had not set the id column as identity in my case - just set it as primary key.
Then you have your answer, use an IDENTITY column.
While Hibernate does choose the right strategy and does generate the appropriate INSERT statements (passing null into the id which is expected to be persisted into an IDENTITY column), it won't create or alter your physical model if you don't use the DDL generation and export capabilities.
I had the same issue when using a JpaSchemaGenerator utility class that I wrote.
When generating the schema for a org.hibernate.dialect.HSQLDialect (where I use a SEQUENCE to generate my unique IDs), I use the following Hibernate property:
hibernate.id.new_generator_mappings=true
This results in the following CREATE statement:
CREATE TABLE BATCH (
BAT_ID NUMBER(19,0) NOT NULL,
BAT_EXPIRY_DATE TIMESTAMP,
BAT_NUMBER VARCHAR2(255 CHAR),
BAT_MAT_ID NUMBER(19,0),
PRIMARY KEY (BAT_ID)
);
But when I use this same property in my utility class to generate a schema using the org.hibernate.dialect.HSQLDialect, I get the following CREATE statement:
CREATE TABLE BATCH (
BAT_ID BIGINT NOT NULL,
BAT_EXPIRY_DATE TIMESTAMP,
BAT_NUMBER VARCHAR(255),
BAT_MAT_ID BIGINT,
PRIMARY KEY (BAT_ID)
);
This would mean that if I created a Batch without an ID, it would not generate it for me and the NOT NULL constraint would cause an exception.
If I change the Hibernate property to the following:
hibernate.id.new_generator_mappings=false
Then it would generate the following CREATE statement:
CREATE TABLE BATCH (
BAT_ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
BAT_EXPIRY_DATE TIMESTAMP,
BAT_NUMBER VARCHAR(255),
BAT_MAT_ID BIGINT,
PRIMARY KEY (BAT_ID)
);
Which works perfectly when creating JPA entities with Hibernate.
Related
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.
JOOQ offers the very nice ability to do the following:
TableRecord tableRecord = dsl.newRecord(TABLE);
tableRecord.setSomeParam(...);
tableRecord.insert();
At this point the record should be inserted in the table.
We can do something like:
tableRecord.getSomeParam(); // will return value above
However, this:
tableRecord.getId(); // NULL
Always returns null. Is this by design? Do we have to use returning(TABLE.ID) to get the autogenerated ID value instead of the Record? Is this behaviour different if the query is executed in a transactional context?
Edit:
I am using PostgreSQL 9.4.10, and my table definition is similar to the following:
CREATE TABLE item
(
id bigserial NOT NULL,
name character varying(245),
some_uuid uuid NOT NULL DEFAULT uuid_generate_v4(),
CONSTRAINT item_pkey PRIMARY KEY (id),
CONSTRAINT item_item_uuid_key UNIQUE (item_uuid)
)
Additional information:
PostgreSQL driver: "postgresql:postgresql>9.1-901.jdbc4"
JOOQ version: 3.8.6
Use store() method (https://www.jooq.org/javadoc/3.2.0/org/jooq/UpdatableRecord.html#store())
Autogenerated ID will be refreshed after storing record.
You could also call record.refresh() after insert, then your record will contain refreshed values.
I have an application using JPA (with eclipselink). The application was developed with a Derby database in the background. The tables were generated by JPA itself. This is a simple example of one of the entities:
public class MyEntity implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(nullable=false)
private String someString;
}
JPA then created another table SEQUENCE to generate the ID.
We now want to switch to PostgreSQL and instead of a table SEQUENCE we want to use real sequences in PostgreSQL. This is the DDL we used to create the table:
CREATE TABLE MYENTITY (
ID serial PRIMARY KEY NOT NULL,
SOMESTRING varchar(255) NOT NULL
)
But still JPA wants to use the SEQUENCE table (that doesn't exist):
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse. persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: relation "sequence" does not exist
Position: 8
Error Code: 0
Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
bind => [2 parameters bound]
Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ? ")
I know that I could change the generation strategy to SEQUENCE, but I want to have the code portable. GenerationType.SEQUENCE shouldn't work with databases that don't support sequences. And I expect that AUTO would use a sequence on PostgreSQL. Why doesn't it? Do I have to do something else?
As a note, it seems that JPA used a sequence automatically in the question Generated Value in Postgres.
If you want to have the id assigned "in datastore" (i.e via auto-generate, or SERIAL) you should use IDENTITY.
Similarly, if you want to use a datastore SEQUENCE then select SEQUENCE.
AUTO means leave it to the JPA implementation to decide, and it may decide something else to what you hoped.
I use play! framework 2.0 and postgresql.
in my db there is users table and every user ofcourse has a unique id.
so I defined it as serial.
my question is: how to represent a field which it's data type is serial
in my java project.
p.s. I understood play! framework uses Hibernate annotation
From the PostgreSQL documentation, the SERIAL type is equivalent to an ìnteger` with a sequence, so:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer DEFAULT nextval('tablename_colname_seq') NOT NULL
);
The #Id JPA annotation on the Long type will provide a sequence (equivalent to AUTO_INCREMENT in MySQL).
So, in you class, just use:
#Id
public Long id;
OK. I just added the annotation #Id
I am trying to create a Spring Roo entity for a legacy database table. The table does not have a primary key defined.
However, Roo will not let me define an entity without an identifierField:
#RooEntity(identifierColumn = "", identifierField = "", table = "XYZ", versionField = "")
This causes the Roo integration tests to fail with:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'id' in 'field list'
Because it creates an #Id and #Column(name = "id") field in Roo_Entity.aj.
I have tried reverse engineering this table with Roo's DBRE function, but all it does is create an identifier class containing all of the fields of the entity. When this happens I cannot add finders for the individual table columns.
As far as I know Roo requires a primary key and strongly suggests a version identifier.
It's possible to use either a simple or a combined primary key. Also looking at DBRE documentation, there is no mention about tables without primary key.
What about fixing the DB? Which DBMS is it? Is it feasible to add a numeric identifier, possibly auto-generated?