JPA/HIbernate integrity constraint violated on cascade - java

I have the following entity which has a relation with WorkFlowDetail class:
#Entity()
#DynamicUpdate()
#Table(schema = "RACQUISTI", name = "RICHIESTA_DI_ACQUISTO")
public class RichiestaDiAcquisto {
#Id
#Column(name = "ID_RICHIESTA_ACQUISTO")
#SequenceGenerator(name="SEQ_GEN",sequenceName="RICHIESTA_DI_ACQUISTO_SEQ", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
private int id;
#OneToOne(fetch=FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinColumn(name="ID_RICHIESTA_ACQUISTO")
private WorkFlowDetail workFlowDetail;
.....
}
The WorkFlowDetail entity is:
#Entity()
#Table(schema = "RACQUISTI", name = "WORKFLOW_DETAIL")
public class WorkFlowDetail {
#Id
#Column(name = "ID_RICHIESTA_ACQUISTO")
private int idRichiestaDiAcquisto;
#Column(name = "ID_WORKFLOW_INSTANCE")
private String idWorkFlowInstance;
....
}
The table WORKFLOW_DETAIL has a foreign key on RICHIESTA_DI_ACQUISTO primary key.
When I execute the following code:
RichiestaDiAcquisto entity = new RichiestaDiAcquisto();
getSession().saveOrUpdate(entity);
I receive this error:
Hibernate: select RICHIESTA_DI_ACQUISTO_SEQ.nextval from dual
Hibernate: select workflowde_.ID_RICHIESTA_ACQUISTO, workflowde_.CURRENT_NODE_ID as CURRENT_2_2_, workflowde_.DATA_MOD as DATA_MOD3_2_, workflowde_.ID_WORKFLOW_INSTANCE as ID_WORKF4_2_, workflowde_.WORKFLOW_TOKEN as WORKFLOW5_2_ from RACQUISTI.WORKFLOW_DETAIL workflowde_ where workflowde_.ID_RICHIESTA_ACQUISTO=?
Hibernate: select richiedent_.ID_RICHIESTA_ACQUISTO, richiedent_.COGNOME as COGNOME2_0_, richiedent_.GODIVA_ANAGRAFICA_ID as GODIVA_A3_0_, richiedent_.NOME as NOME4_0_ from RACQUISTI.RICHIEDENTE richiedent_ where richiedent_.ID_RICHIESTA_ACQUISTO=?
Hibernate: insert into RACQUISTI.RICHIESTA_DI_ACQUISTO (ACQUISTO_DI_BENI, CONFERMA_CAPITOLO, CONFERMA_ELEGIBILITA, COSTO_ACQUISTO, DATA_MOD, DESCRIZIONE_ACQUISTO, GARA_NAZIONALE_CATALOGO, ID_ANAG_MOD, LUOGO_DI_CONSEGNA, SIGLA_ESPERIMENTO, STATUS, STRUTTURA_PAGANTE, ID_RICHIESTA_ACQUISTO) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into RACQUISTI.WORKFLOW_DETAIL (CURRENT_NODE_ID, DATA_MOD, ID_WORKFLOW_INSTANCE, WORKFLOW_TOKEN, ID_RICHIESTA_ACQUISTO) values (?, ?, ?, ?, ?)
WARN 2017-04-28 10:14:28,817 [http-nio-8080-exec-6] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 2291, SQLState: 23000
ERROR 2017-04-28 10:14:28,819 [http-nio-8080-exec-6] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ORA-02291: integrity constraint (RACQUISTI.WORKFLOW_DETAIL_FK1) violated - parent key not found

Your insert statement is trying to insert a value into column which doesn't exist in the RACQUISTI table

I found a solution. I modify the annotation on main class child (WorkFlowDetail):
#Entity()
#DynamicUpdate()
#Table(schema = "RACQUISTI", name = "RICHIESTA_DI_ACQUISTO")
public class RichiestaDiAcquisto {
#Id
#Column(name = "ID_RICHIESTA_ACQUISTO")
#SequenceGenerator(name="SEQ_GEN",sequenceName="RICHIESTA_DI_ACQUISTO_SEQ", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
private int id;
#OneToOne(fetch=FetchType.LAZY, mappedBy = "richiestaDiAcquisto", cascade = {CascadeType.ALL})
private WorkFlowDetail workFlowDetail;
.....
}
Then I modified the child class:
#Entity()
#Table(schema = "RACQUISTI", name = "WORKFLOW_DETAIL")
public class WorkFlowDetail {
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #org.hibernate.annotations.Parameter(name = "property", value = "richiestaDiAcquisto"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "ID_RICHIESTA_ACQUISTO", unique = true, nullable = false)
private int idRichiestaAcquisto;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
private RichiestaDiAcquisto richiestaDiAcquisto;
....
}
Before to save the main class (RichiestaDiAcquisto) I have to put the father on the child class by the following code:
richiestaDiAcquisto.getWorkFlowDetail().setRichiestaDiAcquisto(richiestaDiAcquisto);

Related

Hibernate not set foreign key

I have this model
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToOne
#PrimaryKeyJoinColumn
private Address registred_address_id;
#OneToOne
#PrimaryKeyJoinColumn
private Address actual_address_id;
...
And I have this method
private Customer addCustomer(String first_name, String last_name, String middle_name, String sex, Address address) {
Customer customer = new Customer(first_name, last_name, middle_name, sex);
customer.setActual_address_id(address);
customer.setRegistered_address_id(address);
customerRepo.save(customer);
return customer;
}
But hibernate not set actual_address_id and registered_address_id (it,s OneToOne)
Hibernate:
insert
into
customer
(first_name, last_name, middle_name, sex)
values
(?, ?, ?, ?)
2021-03-18 14:01:58.340 WARN 12836 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 23502
2021-03-18 14:01:58.340 ERROR 12836 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ОШИБКА: значение NULL в столбце "registred_address_id" отношения "customer" нарушает ограничение NOT NULL
Подробности: Ошибочная строка содержит (6, null, null, null, null, null, male).
You mapping is contradictory.
From one side you want Customer.id to be generated by database after its insert. This is what GenerationType.IDENTITY actually mean.
From another side you try to use #PrimaryKeyJoinColumn what mean Customer.id should be set by Address.id. The correct mapping for #PrimaryKeyJoinColumn should look something like this:
#Entity
public class Customer {
#Id
private long id;
#OneToOne
#PrimaryKeyJoinColumn
private Address address;
public void setAddress(Address address) {
this.address = address;
this.id = address.getId();
}
// ...
}
but this will not fit your requirements.
So, I would suggest you correct your customer table like this:
create table customer
(
id bigserial not null,
reg_address_id bigint,
act_address_id bigint,
-- ...
primary key(id),
foreign key(reg_address_id) references address(id),
foreign key(act_address_id) references address(id)
);
and then use the following mapping:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
#JoinColumn(name = "reg_address_id")
private Address registredAddress;
#OneToOne
#JoinColumn(name = "act_address_id")
private Address actualAddress;
// ...
}

Why to use Set in OneToMany Mapping in hibernate

I have two tables with a one-to-many relationship. I want to fetch those records and insert into another database which having same table by changing the primary key.
My application entity class
#Entity
#Table(name = "EM_APPLICATION")
public class ApplicationTable {
#Id
private int APPLICATION_ID;
#Id
private String CUSTOMER_ID;
private String LAST_NAME;
private String FIRST_NAME;
#OneToMany( fetch = FetchType.EAGER,cascade = CascadeType.ALL)
#JoinColumns({ #JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID"),
#JoinColumn(name = "APPLICATION_ID", referencedColumnName = "APPLICATION_ID") })
private Set<AddressTable> address;
//Getters and setters
}
Address entity class..
#Entity
#Table(name="EM_APPL_ADDRESS")
public class AddressTable{
#Id
private int APPLICATION_ID;
#Id
private String CUSTOMER_ID;
#Id
private String ADDRESS_TYPE;
//Getters and setters
}
I have to execute a method for fetching records from DB using hibernate:
public void execute(String applId, String customerId) {
Session session = HibernateQAUtil.openSession();
Transaction tx = session.beginTransaction();
String hql = "FROM ApplicationTable WHERE CUSTOMER_ID =:CUSTOMER_ID AND APPLICATION_ID =:APPLICATION_ID";
Query query = session.createQuery(hql);
query.setParameter("CUSTOMER_ID", customerId);
query.setParameter("APPLICATION_ID", Integer.parseInt(applId));
List<ApplicationTable> list = query.list();
tx.commit();
session.close();
ApplicationTable applVO = list.get(0);
insertApplication(applVO );
}
After fetching the records, I am changing APPLICATION_ID, CUSTOMER_ID and some other columns in address table and after inserting in another database.
private void insertApplication(ApplicationTable emApplVO) {
applVO.setAPPLICATION_ID(123456);
applVO.setCUSTOMER_ID("88888888");
Set<AddressTable> addressSet = emApplVO.getAddress();
for (AddressTable address : addressSet) {
address.setAPPLICATION_ID(123456);
address.setCUSTOMER_ID("88888888");
address.setZIP(500032);
}
Session session1 = HibernateUtil.openSession();
Transaction beginTransaction = session1.beginTransaction();
session1.save(emApplVO);
beginTransaction.commit();
session1.close();
}
Hibernate queries in console log are... (below mentioned queries are too large so copied to some extent only..)
Hibernate: select em_applica0_.CUSTOMER_ID as CUSTOMER1_0_,em_applica0_.APPLICATION_ID as APPLICAT2_0_,em_applica0_.ARCHIVE_IND as ARCHIVE8_0_ where em_applica0_.CUSTOMER_ID=? and em_applica0_.APPLICATION_ID=?
Hibernate: select address0_.CUSTOMER_ID as CUSTOMER1_0_1_, address0_.APPLICATION_ID as APPLICAT2_0_1_, address0_.ADDRESS_TYPE as ADDRESS3_1_0_ where em_applica0_.CUSTOMER_ID=? and em_applica0_.APPLICATION_ID=?
Hibernate: insert into EM_APPLICATION (CUSTOMER_ID, APPLICATION_ID, APPLICATION_NBR, APPLICATION_STATUS, APPLICATION_TYPE) values (?, ?, ?, ?)
Hibernate: insert into EM_APPL_ADDRESS (CUSTOMER_ID, APPLICATION_ID, ADDRESS_TYPE) values (?, ?, ?)
Question 1: in the insert method, I have assigned address to addresSet and made some changes in addresSet, after making those changes, I am not assigned the addressSet to applVO (i.e. not written applVO.setAddress(addresSet )) but it inserted a record with updated values into the Address table. What is happening here?
When I am changing code inside insertApplication(ApplicationTable emApplVO) method to
private void insertApplication(ApplicationTable emApplVO) {
applVO.setAPPLICATION_ID(123456);
applVO.setCUSTOMER_ID("88888888");
Set<AddressTable> addressSet = emApplVO.getAddress();
Set<AddressTable> newAddressSet = new HashSet<AddressTable>();
for (AddressTable address : newAddressSet) {
address.setAPPLICATION_ID(emApplVO.getAPPLICATION_ID());
address.setCUSTOMER_ID(emApplVO.getCUSTOMER_ID());
address.setZIP(500032);
newAddressSet.add(address);
}
emApplVO.setAddress(null);
emApplVO.setAddress(newAddressSet);
Session session1 = HibernateUtil.openSession();
Transaction beginTransaction = session1.beginTransaction();
session1.save(emApplVO);
beginTransaction.commit();
session1.close();
}
Hibernate queries in console log are... It also executing update ...
Hibernate: select em_applica0_.CUSTOMER_ID as CUSTOMER1_0_,em_applica0_.APPLICATION_ID as APPLICAT2_0_,em_applica0_.ARCHIVE_IND as ARCHIVE8_0_ where em_applica0_.CUSTOMER_ID=? and em_applica0_.APPLICATION_ID=?
Hibernate: select address0_.CUSTOMER_ID as CUSTOMER1_0_1_, address0_.APPLICATION_ID as APPLICAT2_0_1_, address0_.ADDRESS_TYPE as ADDRESS3_1_0_ where em_applica0_.CUSTOMER_ID=? and em_applica0_.APPLICATION_ID=?
Hibernate: insert into EM_APPLICATION (CUSTOMER_ID, APPLICATION_ID, APPLICATION_NBR, APPLICATION_STATUS, APPLICATION_TYPE) values (?, ?, ?, ?)
Hibernate: insert into EM_APPL_ADDRESS (CUSTOMER_ID, APPLICATION_ID, ADDRESS_TYPE) values (?, ?, ?)
update EM_APPL_ADDRESS set CUSTOMER_ID=?, APPLICATION_ID=? where CUSTOMER_ID=? and APPLICATION_ID=? and ADDRESS_TYPE=?
Question 2: why is the update query executed?
Question 3: while using List<AddressTable> instead of Set<AddressTable>, I got some errors. What is the difference?

Hibernate not saving into join table - ManyToOne and JoinTable relation

I'm using SpringBoot 2.0.2 with hibernate 5.2.17 and MariaDB 10.1
Customer:
#Entity
public class Customer extends Company {
#ManyToOne(fetch = FetchType.LAZY, cascade = ALL)
#JoinTable(name = "company_services",
joinColumns = #JoinColumn(name = "companyId", insertable = true, updatable = true),
inverseJoinColumns = #JoinColumn(name = "serviceId", insertable = true, updatable = true))
private Service service;
Service:
#Entity
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
With Hibernate log enabled I can see this:
Hibernate:
/* insert com.example.company.Customer
*/ insert
into
`
companies` (
...
)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
select
last_insert_id()
Hibernate:
/* insert com.example.company.Customer
*/ insert
into
`
company_service` (
`serviceId`, `companyId`
)
values
(?, ?)
20:43:53.524 TRACE [cid: none] [session: none] org.hibernate.type.descriptor.sql.BasicBinder -- binding parameter [1] as [BIGINT] - [3]
20:43:53.524 TRACE [cid: none] [session: none] org.hibernate.type.descriptor.sql.BasicBinder -- binding parameter [2] as [BIGINT] - [3]
But when I confirm the result in the db the companies table is OK but the company_services record does not get saved.
Is that a known bug? I'm missing something?
Hibernate does not use join table for many to one relationship. It uses a join column for many to one relationship.

ManyToMany RelationShip NULL not allowed for column

I am trying to make a #ManyToMany relationship between two entities.
Post Entity:
#Entity
#Table(name="Post")
public class Post {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "post_label", joinColumns = #JoinColumn(name = "POST_ID", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "LABEL_ID", referencedColumnName = "id"))
List<Label> labels = new ArrayList<Label>() ;
// getters and setters
}
And Label Entity:
#Entity
#Table(name="Label")
public class Label{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
long id;
String name;
String color;
#ManyToMany(mappedBy = "labels")
List<Post> posts = new ArrayList<Post>() ;
// getters and setters.
}
When I try to save a Post, appears this error:
org.h2.jdbc.JdbcSQLException: NULL not allowed for column "LABEL_ID"; SQL statement:
insert into noticia (id, date, description, facebookid, postedonfacebook, postedonfake, publishdate, subtitle, title, type, visitorscount) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [23502-194]
And similar error when I try to save a Label:
org.h2.jdbc.JdbcSQLException: NULL not allowed for column "NOTICIA_ID"; SQL statement:
insert into label (id, color, name) values (null, ?, ?) [23502-194]
Point 1: I tried to save a Post without adding no Label (same error).
I tried to save a Label without adding no Post (same error)
Point 2: I tried to save a Post adding Label (same error).
I tried to save a Label adding Post (same error)
Your mapping looks fine.
The problem could be in the way you are saving your entities.
Try the following code to persist your Post and its Label child entities.
Post post = new Post();
List<Label> labels = new ArrayList<>();
Label firstLabel = new Label();
firstLabel.setColor("MAROON");
firstLabel.setName("MAROONIFIED");
labels.add(firstLabel);
Label secondLabel = new Label();
secondLabel.setColor("BLUE");
secondLabel.setName("BLUEFIED");
labels.add(secondLabel);
post.setLabels(labels);
postRepository.save(post);
Also check out this answer for h2 specific problem.

Unnecessary updates in #OneToMany

I have model object as follows
Employee.java
#Entity
#Table(name = "EMPLOYEE")
public class Employee {
#Id
#SequenceGenerator(name = "emp_seq", sequenceName = "seq_employee")
#GeneratedValue(generator = "emp_seq")
#Column(name = "EMPLOYEE_ID")
private Integer employeeId;
#Column(name = "EMPLOYEE_NAME")
private String employeeName;
}
Department.java
#Entity
#Table(name = "DEPARTMENT")
public class Department {
#Id
#Column(name = "DEPARTMENT_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer departmentId;
#Column(name = "DEPARTMENT_NAME")
private String departmentName;
#Column(name = "LOCATION")
private String location;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "DEPARTMENT_ID")
private List<Employee> employees = new ArrayList<>();
}
while saving this it is generating two extra update statements.
Test class
Employee e1 = new Employee();
e1.setEmployeeName("Employee-1");
Employee e2 = new Employee();
e2.setEmployeeName("Employee-2");
Department d = new Department();
d.setDepartmentName("Test");
d.setLocation("Test");
d.getEmployees().add(e1);
d.getEmployees().add(e2);
em.getTransaction().begin();
em.persist(d);
em.getTransaction().commit();
on committing the following statements are generated...
Hibernate: insert into DEPARTMENT (DEPARTMENT_NAME, LOCATION, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?
my question here is why 2 extra update(marked by *) statements are needed?
That's the order on which Hibernate does the operations normally. Take a look at this
https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/event/internal/AbstractFlushingEventListener.html#performExecutions%28org.hibernate.event.spi.EventSource%29
According to this documentation:
Execute all SQL (and second-level cache updates) in a special order so
that foreign-key constraints cannot be violated:
When you add Employees to a Department, employees must have a Department ID so that's the reason why Hibernate do an extra update.
If you want to avoid it you can create first the department, and then the employees adding manually Department id
Due to the #OneToMany #JoinColumn(name = "DEPARTMENT_ID") that annotates the attribute Department.employees the table
EMPLOYEE has a foreign key to the table DEPARTMENT. When you persiste the new department with the two employees a new row is inserted into the table DEPARTMENT and two rows are inserted into the table EMPLOYEE but the column DEPARTMENT_ID is null. Then two updates are executed to set this column and relate the EMPLOYEE rows with the DEPARTMENT row.
The question is why this is not done in one step, i.e. instead of executing the following:
Hibernate: insert into DEPARTMENT (DEPARTMENT_NAME, LOCATION, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID) values (?, ?)
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?
**Hibernate: update EMPLOYEE set DEPARTMENT_ID=? where EMPLOYEE_ID=?
the following should be executed:
Hibernate: insert into DEPARTMENT (DEPARTMENT_NAME, LOCATION, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID, DEPARTMENT_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMPLOYEE_NAME, EMPLOYEE_ID, DEPARTMENT_ID) values (?, ?, ?)

Categories

Resources