Hibernate sends NULL for autogenerated field - java

I have entity described as
#Entity(name = "my_entity")
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
it's table is created by Hibernate with
Hibernate: create table my_entity (id integer generated by default as identity,
i.e. it knows that field is autogenerated. Despite that having code
private MyEntity storeNewMyEntity(String fqn) {
MyEntity myEntity = new MyEntity();
myEntity.setFullyQualifiedName(fqn);
return myEntityDao.save(myEntity);
}
it translates it into
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "id"; SQL statement:
insert into my_entity (id,
Why and how to fix?
Dialect is
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

You need to update hibernate-core jar to 5.6.5.Final or any later version, current version in 5.6 branch is 5.6.7.Final and 6.0.0.Final is also already available.
Older versions don't support new versions of H2.

Related

JPA - How to persist an entity having auto generated id and its associated entities

I have an entity class which uses auto generated id from database (PostgreSQL). It has been persisting fine without requiring me to specify an id to it. e.g.
#Entity public class MyEntity {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// ... other columns
}
Now I want to add a List of associated entities owned by this entity class with uni-directional association. e.g.
#Entity public class MyEntity {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(cascade = CascadeType.ALL) #JoinColumn(name="pid")
private List<SubEntity> subEntities;
// ... other columns
}
#Entity public class SubEntity implements Serializable {
#Id private Integer pid; // refer to id of MyEntity
#Id private String name; // pid, name forms a composite key for SubEntity
// ... other columns
}
Then I bumped into an issue that JPA (Hibernate in this case) was generating SQLs like:
INSERT INTO MYENTITY (...) VALUES (...)
INSERT INTO SUBENTITY (pid, ...) VALUES (null, ...)
It failed when trying to insert a null value to pid as it has not null constraint in the database schema. If I bypass this, Hibernate then generates an update statement to update the null value with the generated id from MyEntity:
UPDATE SUBENTITY SET pid = ? WHERE pid = null AND name = ?
I get that the auto generated id is not known until after the insert to MyEntity, so it updates afterward. But I wonder if there is a solution so that Hibernate does the insert to MyEntity ONLY first, get the generated id THEN does the inserts to SubEntity with the correct pid and no update afterward?
This should be possible. Please create an issue in the Hibernate issue tracker with a test case that reproduces this issue. Apart from that, I would suggest you try using a sequence generator as that is more scalable anyway.

org.springframework.dao.DataIntegrityViolationException after update spring-boot from 2.1.x to 2.2.x using hibernate and spring-boot-data-jpa

When trying to update spring-boot from version 2.1.12 to 2.2.4 got stuck on DataIntegrityViolationException when try to insert multiple objects into MySQL using JPA.
Example object:
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Builder(toBuilder = true)
#Table(name = "user")public class User {
#Id
#Column(name = "id")
#JsonProperty("id")
private String id;
#PrimaryKeyJoinColumn
#OneToOne(cascade = CascadeType.ALL)
#JsonProperty("status")
private UserStatus status;
}
And user status:
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "user_status")
public class UserStatus {
#Id
#Column(name = "id")
#JsonProperty("id")
private String id;
public UserStatus(String userId) {
this.id = userId;
}
}
To insert object to mysql I use default jpa repository:
#Repository
public interface UserRepository extends JpaRepository<User, String> {
}
With spring-boot-2.1.x userRepository.save(user) works fine but with 2.2.x it raises this exception:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
With this details in log:
Cannot add or update a child row: a foreign key constraint fails (`test`.`user_status`, CONSTRAINT `user_status_ibfk_1` FOREIGN KEY (`id`) REFERENCES `user` (`id`) ON DELETE CASCADE)
If enable spring.jpa.show-SQL: true I found out that with spring-boot-2.2.x no insertion on User entity is happening but with old spring it is.
I didn't find any major change in spring-boot connecting to hibernate as well as no major change in hibernate itself after the corresponding update.
Is there anything updated which is not described in release notes?
spring-boot 2.1.12 uses Hibernate 5.3.15.Final and spring-boot 2.2.4 uses Hibernate 5.4.10.Final
Your issue seems similar to Hibernate issues HHH-13413 HHH-13171
The reason is in the fix HHH-12436 which was introduced in 5.4.0.CR1 so since then one-to-one mappings don’t work when #OneToOne(mappedBy ="") didn’t provided.
And as I understood from disscussions in JIRA it's not a bug now. There was a bug and they fixed it like so. I guess there is some misunderstanding with #PrimaryKeyJoinColumn so people doesn't use it right.
I guess this will solve the problem
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
#JsonProperty("status")
private UserStatus status;

spring-data-jdbc update with repository save methods updates ID

Calling CrudRepository save() method for an entity that is NOT new creates following sql: UPDATE card SET id = ?, customer_id = ? ... WHERE id = ?
This raises exception Cannot update identity column 'id'
ID is generated by the database
used version: 1.0.6.RELEASE & 1.0.9.RELEASE
DB: mssql
Why is update statement trying to update the ID column as it is the primary key?
Entity:
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
#Table("card")
public class Card {
#Id
private Long id;
#Column("customer_id")
private String customerId;
...
Repository:
public interface CardRepository extends CrudRepository<Card, String> {
}
This sounds like https://jira.spring.io/browse/DATAJDBC-262 which was fixed and released in version 1.1.M1 the current version of that development branch is 1.1.RC1.
Switching to that version should solve the problem.
Note: I've seen the exception you mention only with MS-SqlServer which isn't yet fully supported yet.
It seems that you haven't set id generation Strategy for the ID.
Add this and try if it is working.
#GeneratedValue(strategy = GenerationType.AUTO)

Spring JPA insert entity with id equals null (should be auto generated)

Spring's JpaRepository throws an exception when I try to save entity without id:
MyConfig config = new MyConfig();
config.setValue("value");
myConfigRepository.save(config);
How to make Hibernate not include id field into insert query?
org.h2.jdbc.JdbcSQLException: NULL not allowed for column "MY_CONFIG_ID"; SQL statement:
insert into my_config (value, id) values (?, ?) [23502-190]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.table.Column.validateConvertUpdateSequence(Column.java:305)
at org.h2.table.Table.validateConvertUpdateSequence(Table.java:749)
at org.h2.command.dml.Insert.insertRows(Insert.java:151)
at org.h2.command.dml.Insert.update(Insert.java:114)
at org.h2.command.CommandContainer.update(CommandContainer.java:78)
at org.h2.command.Command.executeUpdate(Command.java:253)
at org.h2.server.TcpServerThread.process(TcpServerThread.java:345)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:159)
at java.lang.Thread.run(Thread.java:745)
my entity:
#Entity
public class MyConfig {
#Id
#SequenceGenerator(sequenceName = "MY_CONFIG_SEQ", name = "MyConfSeq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MyConfSeq")
private Long id;
#Column
private String value;
//getters & setters
and repository:
public interface MyConfigRepository extends JpaRepository<MyConfig, Long>, JpaSpecificationExecutor {}
The column MY_CONFIG_ID is not part of your Hibernate mapping.
The query for insert inserts into the fields id and value. Then, there must be a third column named MY_CONFIG_ID, which is not mentioned in the entity, and thus will be inserted as null. If this column then has a not null constraint, it will fail.
If you want your id-column to be named MY_CONFIG_ID then you need to ovveride the default column name (id, same as the variable) by annotating it with #Column(name="MY_CONFIG_ID"), if you want to use the default name id you would need to remove the column (or at least the not null constraint.)

Hibernate identity primary key generator and foreign keys

Looked in many places and found that the hibernate with postgresql can use an IDENTITY primary key generator which maps into serial/bigserial table column. Suppose i have follow entity:
#Entity
class A {
long id;
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() { return id; }
}
Works good and ddl looks like:
create table A (id bigserial)
Unfortunatelly any attempt to reference to 'a' via #ManyToOne produces the foreign key column which is also bigserial.
#Entity
class B {
// id ommitted ...
A a;
#ManyToOne
public A getA() {
return a;
}
}
generates ddl like follow:
create table B (..., a_id bigserial)
In most cases this will work ok. But the logically it is completly wrong. a_id has nothing to do with bigserial "datatype" either.
It there any way to tell hibernate to use bigint for column a_id in the table B ?
Tried to override with columnDefinition in the #JoinColumn or #Column annotations for a getter with no luck. Hibernate completly ignores these annotation attributes.

Categories

Resources