I need to use the GenerationType.sequence strategy for a table
I write the follow annotation in the class:
#Id
#SequenceGenerator(name="SEQ_PERFIL", sequenceName="SEQ_PERFIL",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_PERFIL")
#Column(name="PER_CODPERFIL", nullable = false)
private long perCodperfil;
To insert I use this code:
entityManager.getTransaction().begin();
entityManager.persist(entity);
entityManager.flush();
entityManager.refresh(entity);
entityManager.getTransaction().commit();
When I insert the sequence is incremented (I show that in the database), but the insertion fail, because the primary key is null
It said :
Error Code: 1400
Call: INSERT INTO PERFIL (PER_CODPERFIL) VALUES (?) bind => [1 parameters bound]
Query: InsertObjectQuery(24)
and it said that PER_CODPERFIL is null
I use Eclipse-link and a Oracle DB
The sentence loggued by eclipse link is :
15:05:36,651 INFO [EclipseLog] SELECT SEQ_SIAC_PERFIL.NEXTVAL FROM DUAL
15:05:36,761 INFO [EclipseLog] INSERT INTO PERFIL (PER_CODPERFIL) VALUES (?) bind => [null]
15:05:36,773 INFO [EclipseLog] SELECT 1 FROM DUAL
Related
I can't save result of select into database using JPA in Spring Boot application. The code that I use is below:
#Override
#Transactional
public void fetchAndSave() {
List<TestData> all = testDataRepository.findAllRecords();
testDataRepository.saveAll(all);
// let suppose I will save another data here that's why I need #Transactional for roll-back in case of exception
}
#Repository
public interface TestDataRepository extends JpaRepository<TestData, Long> {
#Query(value = "select raw_values.identificator AS id, raw_values.name as value from test.raw_values", nativeQuery = true)
List<TestData> findAllRecords();
}
When I call fetchAndSave with a property spring.jpa.show-sql=true I see in logs only select:
Hibernate: select raw_values.identificator AS id, raw_values.name as value from test.raw_values
In a case I don't use #Transactional I can see more requests to database in logs and values are saved:
Hibernate: select raw_values.identificator AS id, raw_values.name as value from test.raw_values
Hibernate: select testdata0_.id as id1_0_0_, testdata0_.value as value2_0_0_ from test.test_data testdata0_ where testdata0_.id=?
Hibernate: select testdata0_.id as id1_0_0_, testdata0_.value as value2_0_0_ from test.test_data testdata0_ where testdata0_.id=?
Hibernate: select testdata0_.id as id1_0_0_, testdata0_.value as value2_0_0_ from test.test_data testdata0_ where testdata0_.id=?
Hibernate: insert into test.test_data (value, id) values (?, ?)
Hibernate: insert into test.test_data (value, id) values (?, ?)
Hibernate: insert into test.test_data (value, id) values (?, ?)
I have a pretty simple table in database, DDL looks like:
create table test_data
(
id serial not null
constraint test_data_pk
primary key,
value varchar(256)
);
-- There are 3 records in table raw_values
create table table_name
(
identificator integer not null
constraint table_name_pk
primary key,
name varchar(256)
);
Can you help me to identify the reason of such behavior? I expect records to be saved into database when I use #Transactional.
The short answer for "why it does not save" is: because they are already saved.
The longer answer is Hibernate sees that these IDs has already present in DB, and it does not save them.
If you want to inset another three entities to DB, just create duplicates for these objects, with id=null and save them:
List<TestData> all = testDataRepository.findAllRecords();
List<TestData> copies = all.stream()
.map(testData -> new TestData(...)) //copy all the fields EXCEPT ID
.collect(toList());
testDataRepository.saveAll(copies);
My requirement is to make hibernate fetch the latest value for PI already available in existing table and add new record by incrementing the the max PI value by one.
Below is my Entity class implementation
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
private String name;
}
Below is my class through which I enter value in User table
#PostMapping("/jpa/users")
public void addUser(#Valid #RequestBody User user)
{
User saved = userRepository.save(user);
}
My user table already has below values before I start my application
id name
1 sample_name_1
2 sample_name_2
Now when I start my application and try inserting new value in User table it should enter new record with PI as 3
Example: Below is JSON request body (Input)
{
"name": "sample_name_3"
}
It gives the below error
{
"timestamp": "2018-05-01T23:09:31.806+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not execute statement; SQL [n/a]; constraint [\"PRIMARY KEY ON PUBLIC.USER(ID)\"; SQL statement:\ninsert into user (name, id) values (?, ?) [23505-197]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
"path": "/jpa/users"
}
I understand it is having PrimaryIndex contraint error. It is trying to insert new record with PI as 1
If my user table is empty and when I insert couple of records, it adds new auto-incremented values.
So, I think Hibernate is not reading the latest value of id column from user table.
What annotation should I used to make hibernate read the latest value of id everytime before inserting new record.
PS: I've already tried below strategy and none of it works
GenerationType.TABLE
GenerationType.AUTO
GenerationType.SEQUENCE
GenerationType.IDENTITY
The generation type you want to use is GenerationType.IDENTITY, however you need to
use a database which supports identity columns, and
correctly define your primary key column to be an identity column.
So for example in PostgreSQL, you would define your primary key column like this:
CREATE TABLE mytable (
id serial primary key,
...
Definitive information about this is available in the JPA specification under section 11.1.20 GeneratedValue Annotation.
I'am trying to do an unidirectional #OneTaMany relationship like in the Hibernate User Guide (2.7.2) but when I try to save the following object in a MariaDB Database:
Filter filter = new Filter("TLS_A320");
filter.addConstraint(new Constraint(ConstraintType.DEPARTURE, "TLS"));
filter.addConstraint(new Constraint(ConstraintType.AIRCRAFT, "A320"));
session.save(filter);
I got this exception :
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Filter_idFilter' in 'field list'
Here are the 2 classes:
Filter.java
public class Filter {
#Id
#Column(name = "idFilter")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<Constraint> constraintList;
//more code
};
Constraint.java
public class Constraint {
#Id
#Column(name = "idConstraint")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "type")
#Enumerated(EnumType.ORDINAL)
private ConstraintType constraintType;
#Column(name = "value")
private String value;
//more code
}
And here is the tables definition :
CREATE TABLE `Constraint` (
idConstraint INT NOT NULL AUTO_INCREMENT,
type INT NOT NULL,
value VARCHAR(10) NOT NULL,
PRIMARY KEY (idConstraint)
);
CREATE TABLE Filter (
idFilter INT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
PRIMARY KEY (idFilter)
);
CREATE TABLE Filter_Constraint (
idFilter INT UNIQUE NOT NULL,
idConstraint INT NOT NULL,
CONSTRAINT fk_Filter_Constraint_Filter FOREIGN KEY (idFilter) REFERENCES Filter(idFilter),
CONSTRAINT fk_Filter_Constraint_Constraint FOREIGN KEY (idConstraint) REFERENCES `Constraint`(idConstraint)
);
It seems to me that that Filter and Constraint insertions are fine and the exception happens when inserting in the Filter_Constraint table :
DEBUG org.hibernate.SQL - insert into Filter (name) values (?)
DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 4
DEBUG org.hibernate.SQL - insert into `Constraint` (type, value) values (?, ?)
DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 5
DEBUG org.hibernate.SQL - insert into `Constraint` (type, value) values (?, ?)
DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 6
DEBUG org.hibernate.SQL - insert into `Filter_Constraint` (Filter_idFilter, `constraintList_idConstraint`) values (?, ?)
DEBUG org.hibernate.engine.jdbc.spi.SqlExceptionHelper - could not execute statement [n/a]
DEBUG com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Filter_idFilter' in 'field list'
I'am pretty new to Hibernate and I just can't figure out what I did wrong.
You didn't define any join column or inverse join column on constraintList, hence Hibernate will autogenerate column names which most probably results in the name Filter_idFilter.
The entity name will be part of the name since Constraints could have an id field with the same name, i.e. idFilter. Of course you know that isn't the case but Hibernate doesn't (or at least the column name generation code isn't that complex) and hence it has to assume that could be the case.
The same is true for join table names so you'll probably want to use #JoinTable along with the definition of join columns and inverse join columns on constraintList. However, since the relation is OneToMany anyways, why don't you add a back reference to Constraint, add the filter's id to table Constraint and get rid of the join table entirely?
I have a table, which has a column "description" of type TEXT. If I do:
SELECT id, description FROM table_name;
I see in "description" column instead of text value a number. Is there any way to see the text value?
Edit: After some testing I found out why I see numbers, but others like Craig see real text. It's because the data are inserted using Hibernate.
Entity:
#Entity
public class Settings {
#Id
#GeneratedValue
private Integer id;
#Column(nullable = false, unique = true)
private String key;
#Lob
#Column(nullable = false, length = Integer.MAX_VALUE)
private String value;
// getters and setters
}
Log result:
Hibernate: create table Settings (id int4 not null, key varchar(255) not null, value text not null, primary key (id));
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into Settings (key, value, id) values (?, ?, ?)
16:05:32,718 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [GoogleSiteVerification]
16:05:32,718 TRACE BasicBinder:81 - binding parameter [2] as [CLOB] - []
16:05:32,726 TRACE BasicBinder:81 - binding parameter [3] as [INTEGER] - [4]
If I do in pgAdmin3 this select:
select * from settings;
I see this result:
1;"GoogleSiteVerification";"112351"
Added #Type(type = "org.hibernate.type.TextType") to attribute annotated with #Lob. Now it works as desired.
Also it solved the issue with encoding, which was the reason I opened pgAdmin in the first place (to see what's inside).
Technical detail: PostgreSQL stored LOB in separate place and referenced it by a numerical identifier (which was what the number which confused me).
Setup:
CREATE TABLE table_name (id integer, description text);
INSERT INTO table_name(id, description) values (1, '12');
Demo:
testdb=> SELECT id, description FROM table_name;
id | description
----+-------------
1 | 12
(1 row)
Yup, I'd say you have a number in your description column because there's a number in your description column.
I've mapped my class as follow (omitted other fields as only ID matters):
#Entity
#Table(name = "MODEL_GROUP")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class SettlementModelGroup implements Serializable
{
#Id
#GeneratedValue(generator = "MODEL_GROUP_SEQ", strategy = GenerationType.SEQUENCE)
#GenericGenerator(name = "MODEL_GROUP_SEQ",
strategy = "sequence",
parameters = #Parameter(name = "sequence", value = "SEQ_MODEL_GROUP_MODEL_GROUP_ID"))
#Column(name = "MODEL_GROUP_ID", nullable = false)
private Integer modelId;
}
when I'm saving new object:
Integer modelGroupId = sessionFactory.getCurrentSession().save( modelGroup );
System.out.println( modelGroupId );
ID is set as for example 23, but when I look at the database it is actually 24. This is leading to many problems, as I'm using this ID later on. Any idea why it is making this gap?
SQL logs show that everything is fine (I thinks so):
Hibernate:
select
SEQ_MODEL_GROUP_MODEL_GROUP_ID.nextval
from
dual
Hibernate:
insert
into
MODEL_GROUP
(DOMAIN_ID, DESCRIPTION, NAME, PERIOD_TYPE_ID, MODEL_GROUP_TYPE_ID, STATUS_ID, OWNER_ID, MODEL_GROUP_ID)
values
(?, ?, ?, ?, ?, ?, ?, ?)
Trigger and Sequence:
CREATE SEQUENCE "SEQ_MODEL_GROUP_MODEL_GROUP_ID"
INCREMENT BY 1
START WITH 1
NOMAXVALUE
MINVALUE 1
NOCYCLE
NOCACHE
NOORDER
;
CREATE OR REPLACE TRIGGER "TRG_MODEL_GROUP_MODEL_GROUP_ID"
BEFORE INSERT
ON "MODEL_GROUP"
FOR EACH ROW
WHEN (NEW."MODEL_GROUP_ID" is NULL)
BEGIN
SELECT "SEQ_MODEL_GROUP_MODEL_GROUP_ID".NEXTVAL
INTO :NEW."MODEL_GROUP_ID"
FROM DUAL;
END;
Apparently, when Hibernate ask your database for nextValue of ID, it fires also Trigger. So when I ask for ID, I've got number 23 but when actually saving to database by commiting transaction, it is increased again so I've got 24. Solution is described here:
HIbernate issue with Oracle Trigger for generating id from a sequence
To make it work correctly, I changed Trigger:
CREATE OR REPLACE TRIGGER "TRG_MODEL_GROUP_MODEL_GROUP_ID"
BEFORE INSERT
ON "MODEL_GROUP"
FOR EACH ROW
WHEN (NEW."MODEL_GROUP_ID" is NULL)
BEGIN
SELECT "SEQ_MODEL_GROUP_MODEL_GROUP_ID".NEXTVAL
INTO :NEW."MODEL_GROUP_ID"
FROM DUAL;
END;