org.hibernate.exception.ConstraintViolationException: could not insert - java

When I try to add into TDEPOFAZLA table, I get the following error:
org.springframework.dao.DataIntegrityViolationException: could not insert: [tr.gov.tcmb.pgmtems.model.DepoFazla]; SQL [insert into PGMTEMS.TDEPOFAZLA (ID, FAZLABULUNDURMAORANI, GRUP) values (default, ?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [tr.gov.tcmb.pgmtems.model.DepoFazla]
Here is my JUnit test function:
#Test
public void testSaveDepoFazla() {
DepoTur depoTur = new DepoTur("my tür", 5);
depoTurService.saveDepoTur(depoTur);
List<DepoTur> list = depoTurService.getDepoTurList();
assertNotNull(list.get(0));
BigDecimal fazlaBulundurmaOrani = new BigDecimal(6000);
DepoFazla depoFazla = new DepoFazla(1, list.get(0), fazlaBulundurmaOrani);
depoFazlaService.saveDepoFazla(depoFazla);
}
Here is my DepoFazla.java:
#Entity
#Table(schema = "PGMTEMS", name = "TDEPOFAZLA")
public class DepoFazla implements Serializable {
private static final long serialVersionUID = -2800365387332643658L;
#Id
#GeneratedValue
#Column(name = "ID", nullable = false, updatable = false)
private Long id;
#Column(name = "GRUP", nullable = false, columnDefinition = "INTEGER")
private Integer grup;
#ManyToOne(fetch = FetchType.LAZY, targetEntity = DepoTur.class)
#JoinColumn(name = "ID", insertable = false, updatable = false)
#NotNull
private DepoTur depoTur;
#Column(name = "FAZLABULUNDURMAORANI", nullable = false, columnDefinition = "DECIMAL(6, 2)")
private BigDecimal fazlaBulundurmaOrani;
public DepoFazla() {
super();
}
public DepoFazla(Integer grup, DepoTur depoTur, BigDecimal fazlaBulundurmaOrani) {
super();
this.grup = grup;
this.depoTur = depoTur;
this.fazlaBulundurmaOrani = fazlaBulundurmaOrani;
}
//GETTER AND SETTER METHODS
}
Here is DepoTur.java:
#Entity
#Table(schema = "PGMTEMS", name = "TDEPOTUR")
public class DepoTur implements Serializable {
private static final long serialVersionUID = 6203672609079710060L;
#Id
#GeneratedValue
#Column(name = "ID", nullable = false, updatable = false)
#Index(name = "XUTDEPOTURP", columnNames = { "id" })
private Long id;
#Column(name = "ACIKLAMA", nullable = false)
private String aciklama;
#Column(name = "BLOKESIRASI", nullable = false)
private Integer blokeSirasi; //
#Column(name = "DEPOCINSI")
private String depoCinsi;
public DepoTur() {
super();
}
public DepoTur(String aciklama, Integer blokeSirasi, String depoCinsi) {
super();
this.aciklama = aciklama;
this.depoCinsi = depoCinsi;
this.blokeSirasi = blokeSirasi;
}
public DepoTur(String aciklama, Integer blokeSirasi) {
super();
this.aciklama = aciklama;
this.blokeSirasi = blokeSirasi;
}
//GETTER AND SETTER METHODS
When I debug the JUnit test, I get this error:
Error: DB2 SQL Error: SQLCODE=-407, SQLSTATE=23502, SQLERRMC=TBSPACEID=2, TABLEID=75, COLNO=2, DRIVER=3.50.152 SQLState: 23502 ErrorCode: -407
When I search the error, I find that I try to insert NULL but I can't figure out where I add null value.
This is how I create TDEPOFAZLA table:
CREATE TABLE TDEPOFAZLA
(
ID decimal(20,0) PRIMARY KEY NOT NULL,
GRUP int NOT NULL,
DEPOTUR decimal(20,0) NOT NULL,
FAZLABULUNDURMAORANI decimal(6,2) NOT NULL
);
CREATE UNIQUE INDEX XUTDEPOFAZLAP ON TDEPOFAZLA(ID);
This is how I create TDEPOTUR table:
CREATE TABLE TDEPOTUR
(
ID decimal(20,0) PRIMARY KEY NOT NULL,
ACIKLAMA varchar(100) NOT NULL,
DEPOCINSI char(1),
BLOKESIRASI int NOT NULL
);
CREATE UNIQUE INDEX XUTDEPOTURP ON TDEPOTUR(ID);
Any ideas on what I should do?

Your property definition with the FK is wrong, as i saw you use updatable, insertable to false, you what really want is that the FK object is not modified because could be a master table common for some other entities.
Then what you can use is this
#ManyToOne(cascade= {CascadeType.DETACH})
#JoinColumn(name = "DEPOTUR")
#NotNull
private DepoTur depoTur;
With DETACH, you will save the value only in the first table, column DEPOTUR and wont update the object in the DepoTur table
Also add the FK in your first table
CREATE TABLE TDEPOFAZLA
(
ID decimal(20,0) PRIMARY KEY NOT NULL,
GRUP int NOT NULL,
DEPOTUR decimal(20,0) NOT NULL,
FAZLABULUNDURMAORANI decimal(6,2) NOT NULL
);
CREATE UNIQUE INDEX XUTDEPOFAZLAP ON TDEPOFAZLA(ID);
CONSTRAINT fk_column FOREIGN KEY (DEPOTUR) REFERENCES TDEPOTUR(ID);

The problem was that I didn't reference the join column properly. This solved the problem:
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "DEPOTUR", referencedColumnName = "ID", nullable = false, columnDefinition = "DECIMAL(20,0)")
#NotNull
private DepoTur depoTur;

It appears that you specified the same name for the join column Id twice in your DepoFazla model you have to change its name use for example :
#Entity
#Table(schema = "PGMTEMS", name = "TDEPOFAZLA")
public class DepoFazla implements Serializable {
private static final long serialVersionUID = -2800365387332643658L;
...
#ManyToOne(fetch = FetchType.LAZY, targetEntity = DepoTur.class)
#JoinColumn(name = "ID_depoTur", insertable = false, updatable = false)
#NotNull
private DepoTur depoTur;
...
}

Related

Hibernate One-to-One, When inserting, Why FK is null

When I run this code, it is running with out error. But When I check the values, as you can see, In the "Tbl_InstructorDetail" table the parentId is null
can anyone help.
thank you.
This is my Entities and my main class with table relation
enter image description here
this is my tables from my database
create table Tbl_Instructor
(
uuid int identity
constraint Pk_Tbl_Instructor_uuid
primary key,
Title nvarchar(50)
)
create table Tbl_InstructorDetail
(
uuid int identity
constraint Pk_Tbl_InstructorDetail_uuid
primary key,
Created_By nvarchar(50),
parentId int
constraint Fk_Tbl_InstructorDetail_Tbl_Instructor
references Tbl_Instructor
)
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
#Basic
#Column(name = "parentId", nullable = true,insertable = false,updatable = false)
private Integer parentId;
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
Main class
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
instructor.setDetailEntity(detail);
session.getTransaction().begin();
session.save(instructor);
session.getTransaction().commit();
You don't need to add parentId in TblInstructorDetailEntity because it's referenced from TblInstructorEntity. In main class foreign key pass null because you can take a reference to the parent table before save parent table.
Here down is modified code:
Entity
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
// remove parentId column because it is foreign key
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
// getter setter
}
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
// getter setter
}
Main
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
session.save(instructor); // Save parent entity
detail.setInstructorEntity(instructor); // Reference from parent entity
session.save(detail); // Save child entity
session.getTransaction().commit();
HibernateUtil.shutdown();

Many to many on delete set NULL

I have a many to many relationship between user and group with addtional columns in the join table. It looks like this:
When I delete an user, it should remove all his references from user_to_group(which works) and all the groups created by him should remain and have their created_by field updated to NULL(this doesn't happen, all the entries are deleted).
DDL for schema:
CREATE TABLE user (
user_id int NOT NULL AUTO_INCREMENT,
first_name varchar(100) NOT NULL,
last_name varchar(100) NOT NULL,
username varchar(100) NOT NULL,
email_address varchar(100) UNIQUE NOT NULL,
phone_number varchar(100) NOT NULL,
password varchar(255) NOT NULL,
notification_type varchar(30) NOT NULL DEFAULT "email",
date_created datetime NOT NULL,
is_active bool NOT NULL DEFAULT false,
CONSTRAINT user_pk PRIMARY KEY (user_id)
);
CREATE TABLE `group` (
group_id int NOT NULL AUTO_INCREMENT,
name varchar(100) NULL,
date_created datetime NOT NULL,
is_private bool NOT NULL DEFAULT false,
created_by int NULL,
CONSTRAINT group_pk PRIMARY KEY (group_id),
CONSTRAINT group_user_fk FOREIGN KEY(created_by)
REFERENCES user (user_id) ON DELETE SET NULL
);
CREATE TABLE user_to_group (
user_id int NOT NULL,
group_id int NOT NULL,
user_type_id int NOT NULL,
is_blocked bool NOT NULL DEFAULT false,
CONSTRAINT user_to_group_pk PRIMARY KEY (user_id,group_id),
CONSTRAINT user_to_group_group_fk FOREIGN KEY(group_id)
REFERENCES `group` (group_id),
CONSTRAINT user_to_group_user_type_fk FOREIGN KEY(user_type_id)
REFERENCES user_type (id),
CONSTRAINT user_to_group_user_fk FOREIGN KEY(user_id)
REFERENCES user (user_id)
);
User Entity:
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "username",
unique = true)
private String username;
#Column(name = "email_address",
unique = true)
private String emailAddress;
#Column(name = "phone_number")
private String phoneNumber;
#Column(name = "password")
private String password;
#Column(name = "notification_type",
insertable = false)
private String notificationType = "email";
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "is_active",
insertable = false)
private Boolean active = false;
#OneToMany(
mappedBy = "user",
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true
)
private List<UserGroup> groups;
}
Group Entity:
#Entity
#Table(name = "`group`")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "group_id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "is_private",
insertable = false)
private Boolean privateG = false;
#OneToOne(fetch = FetchType.LAZY,
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true)
#JoinColumn(name = "created_by")
private User createdBy;
#OneToMany(
mappedBy = "group",
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true
)
private List<UserGroup> users = new ArrayList<>();
}
UserGroup(join table):
#Entity
#Table(name = "user_to_group")
public class UserGroup {
#EmbeddedId
private UserGroupId id;
#ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#MapsId("userId")
#JoinColumn(name = "user_id", insertable = false, updatable = false)
private User user;
#ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#MapsId("groupId")
#JoinColumn(name = "group_id", insertable = false, updatable = false)
private Group group;
#Column(name = "is_blocked",
insertable = false)
private boolean isBlocked = false;
}
Ignore user_type_id field on the join table. If I delete an user with on the workbench, it works as expected(created_by field updates to NULL). But if i use this:
#Override
#Transactional
public User deleteUser(Long id) {
Optional<User> userToDelete = userRepository.findById(id);
userToDelete.ifPresent(user -> userRepository.delete(user));
return userToDelete.orElseThrow(() -> new UserNotFoundException("User not found"));
}
the entire row in the group table is deleted. What am I doing wrong?
#ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#MapsId("groupId")
#JoinColumn(name = "group_id", insertable = false, updatable = false)
private Group group;
exclude CascadeType.REMOVE and group will be intact.

Unidirectional OneToMany with Composite Primary key not persisted

I have an ER relationship from a legacy DB (MS SQL Server based as below
The way that I'm currently trying to convert this to the JPA 2.1 style is as below
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Orders implements Serializable {
#Id
#GeneratedValue
#Column(name = "OrderNumber", nullable = false)
private Integer orderNumber;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "OrderHistory",
joinColumns = {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false)
}
)
private List<OrderHistory> orderHistory;
----Other properties, Getters and Setters
}
#Entity
#PrimaryKeyJoinColumn(name = "OrderNumber")
public class SpecialOrders extends Orders implements Serializable {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false)
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#Fetch(FetchMode.SELECT)
#OrderBy("sequenceNumber ASC")
private List<Items> items;
----Other properties, Getters and Setters
}
#Entity
#IdClass(ItemsPK.class)
public class Items implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "CustomOptions",
joinColumns = {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false),
#JoinColumn(name = "SequenceNumber", referencedColumnName = "SequenceNumber", nullable = false)
}
)
private List<CustomOptions> customOptions;
----Other properties, Getters and Setters
}
#Entity
public class ItemsPK implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
----Getters and Setters
}
#Entity
#IdClass(CustomOptionsPK.class)
public class CustomOptions implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#Id
#Column(name = "OptionNumber", nullable = false)
private Integer optionNumber;
----Other properties, Getters and Setters
}
public class CustomOptionsPK implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#Id
#Column(name = "OptionNumber", nullable = false)
private Integer optionNumber;
----Getters and Setters
}
With the above code, I see that hibernate does below
INSERTs into Orders and gets the GeneratedId for OrderNumber
INSERTs into SpecialOrders, using the orderNumber retrieved above.
Attemps to INSERT into Items table, with a NULL value in the orderNumber and then fails because the orderNumber is a NOT NULL column.
Subsequently, If add a "Simple" primary key to Items table and make the orderNumber as a NULLable column, then the below happens:
INSERTs into Orders and gets the GeneratedId for OrderNumber
INSERTs into SpecialOrders, using the orderNumber retrieved above.
INSERTs into Items table with orderNumber as NULL value and gets the generated id of the Items table row.
Updates the row of Items table with the orderNumber from parent, using the retrieved id for Items.
Attemps to INSERT into CustomOptions table, with a NULL value in the orderNumber and then fails because the orderNumber is a NOT NULL column.
As per the above sequence, it seems that:
Composite Primary key doesnt seem to be working correctly or not supported.
Hibernate is handling the OneToMany relationship inefficiently by issuing an INSERT followed by an UPDATE, instead of just an insert.
Any idea if my understanding is correct? The only way of fixing this issue seems to be that I need to remove the composite primary key and replace it with a simple one.

Unable to convert between java.lang.Integer and BINARY.- Spring

I have the following DTO that I use to persist new records to my database
#Entity(name = "User")
public class User {
#Id
#Column(name = "User_Id")
private long userId;
#Column(name = "User_Name")
private String userNm;
#Column(name = "years_active")
private long years;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "Manager_Id", insertable = false, updatable = false)
private Manager manager;
#Column(name = "Projects",insertable = false, updatable = false)
private LinkedHashMap<Long, String> projects;
#Column(name = "Projects")
private long projectId;
#Column(name = "address")
private Address address;
//getters & setters
}
DDL:
CREATE TABLE [dbo].[User] (
[User_Id] int NOT NULL,
[User_Name] varchar(255) NOT NULL,
[years_active] int NOT NULL,
[Manager_id] int NOT NULL, //FK to Manager table
[Projects] int NOT NULL, //FK to Project table
[Address] int NULL, //FK to Address Table
[ModifiedBy] varchar(255) NOT NULL,
[ModifiedTS] datetime NULL)
I have no problem persisting data to this table via form submission, however when I try to retrieve an entity object using Spring Repository:
User user = userRepo.findOne(id); // id == Long, passed through #Controller method
I consistently get the following error : Unable to convert between java.lang.Integer and BINARY.
o.h.engine.jdbc.spi.SqlExceptionHelper : Unable to convert between java.lang.Integer and BINARY.
o.h.e.internal.DefaultLoadEventListener : HHH000327: Error performing load command :
org.hibernate.exception.DataException: Could not read entity state from ResultSet : EntityKey[com.myapp.entities.User#3]
I'm not sure where this conversion between integer and Binary is happening; any ideas?

JPA many-to-one with constant values in referenced table

I'm doing Spring Boot project and use spring-boot-jpa (Hibernate implementation). I'm having trouble configuring following relation between entities.
Let's assume I need many-to-one (and reversly one-to-many) relation between two tables (MySQL in this example, table1 logically stores description for codes in various other tables) :
CREATE TABLE `table1` (
`id` INT NOT NULL AUTO_INCREMENT,
`ref_table` VARCHAR(50) NOT NULL,
`ref_column` VARCHAR(50) NOT NULL,
`code` VARCHAR(10) NOT NULL,
`description` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `u_composite1` (`ref_table` ASC, `ref_column` ASC, `code` ASC));
CREATE TABLE `table2` (
`id` INT NOT NULL AUTO_INCREMENT,
`field1` VARCHAR(100) NULL,
`code` VARCHAR(10) NOT NULL,
PRIMARY KEY (`id`));
The way I join these two tables in SQL is like this:
SELECT t2.*, t1.description
FROM table2 t2
JOIN table1 t1
ON ( t1.ref_table = 'table2'
AND t1.ref_column = 'code'
AND t1.code = t2.code);
So, I created entities like this (minus the getters an setters):
#Entity
#Table(name = "table1")
public class Table1 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private int id;
#Column(nullable = false, length = 10)
private String code;
#Column(length = 100)
private String description;
#Column(name = "ref_column", nullable = false, length = 50)
private String refColumn;
#Column(name = "ref_table", nullable = false, length = 50)
private String refTable;
#OneToMany(mappedBy = "table1")
private List<Table2> table2;
}
#Entity
#Table(name = "table2")
public class Table2 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private int id;
#Column(nullable = false, length = 45)
private String field1;
#ManyToOne(fetch=FetchType.LAZY)
#Column(name = "code")
#JoinColumns({
#JoinColumn(name = "code", referencedColumnName = "code", nullable = false, updatable = false),
#JoinColumn(name = "'table2'", referencedColumnName = "ref_table", nullable = false, updatable = false),
#JoinColumn(name = "'code'", referencedColumnName = "ref_column", nullable = false, updatable = false)
})
private Table1 table1;
}
But it doesn't work. :(
Can this kind of relation even be defined in JPA?
If so, please, how?
Pertaining to the "join with constant values" problem I managed to make it work using the #Where Hibernate annotation:
How to replace a #JoinColumn with a hardcoded value?
#Entity
#Table(name = "a")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public long id;
#OneToMany
#JoinColumn(name = "id", referencedColumnName = "id")
#Where(clause = "blah = 'CONSTANT_VALUE'")
public Set<B> b;
protected A() {}
}
#Entity
#Table(name = "b")
public class B {
#Id
#Column(nullable = false)
public Long id;
#Column(nullable = false)
public String blah;
protected B() {}
}

Categories