Hibernate not set foreign key - java

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;
// ...
}

Related

Hibernate trying to alter table before creating it

Simple issue here: I'm running Spring Boot 2.2.5 on a mySQL database with MySQL5Dialect. Everything was peachy until I've added #ManyToOne annotation to Slide entity referencing the User entity - now Hibernate can't create tables because it creates the users table and then tries to alter slides table which it hasn't created yet. What did I do wrong?
User:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private boolean enabled;
private String token;
private String username;
private String password;
private String role;
private String name;
private String surname;
private String email;
private boolean emailVisible;
private String phone;
private boolean phoneVisible;
private int cohortNumber;
private String company;
private String position;
private String linkedIn;
private String function;
private String bio;
private String membership;
private Date membershipSince;
private Date membershipUntil;
}
Slide:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString(exclude = "editor")
#Table(name = "slides")
public class Slide {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private boolean visible;
private int order;
private Date edited;
#ManyToOne
#JoinColumn(name = "editor_id")
private User editor;
private String title;
private String text;
private String picture;
}
Hibernate config specifics:
spring.jpa.hibernate.ddl-auto = update
spring.datasource.initialization-mode=always
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
And the error:
Hibernate: create table users (id integer not null auto_increment, bio varchar(255), cohort_number integer not null, company varchar(255), email varchar(255), email_visible bit not null, enabled bit not null, function varchar(255), linked_in varchar(255), membership varchar(255), membership_since datetime, membership_until datetime, name varchar(255), password varchar(255), phone varchar(255), phone_visible bit not null, position varchar(255), role varchar(255), surname varchar(255), token varchar(255), username varchar(255), primary key (id)) engine=MyISAM
Hibernate: alter table slides add constraint FKobqxptfxg36ls278o63ouq369 foreign key (editor_id) references users (id)
2020-08-11 14:27:48.201 WARN 8224 --- [ restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl : GenerationTarget encountered exception accepting command : Error executing DDL "alter table slides add constraint FKobqxptfxg36ls278o63ouq369 foreign key (editor_id) references users (id)" via JDBC Statement
...
Caused by: java.sql.SQLSyntaxErrorException: Table '32293814_alumnicemba.slides' doesn't exist
Found the problem:
private int order;
"order" is not allowed as a field name here and Hibernate was encountering an error when trying to create the slides table but not logging that error. I've renamed the field to "sorting" and it works now.

Why does Hibernate require a #GeneratedValue for cascading?

I want to persist an entity which both doesn't have a generated value for the identifier and also cascade persists another entity. However this combination doesn't seem to be possible. I'm using Spring Data JPA for saving the entities.
Let's say you have two entities, for e.g. Student and Address. For students you want to keep their registration date (let's assume it's always unique), name and address. From the address you want to only save the street for simplicity sake. When saving the Student entity you want to cascade persist the Address entity. So you create the following entities.
#Entity
public class Student {
#Id
private LocalDateTime registrationDateTime;
#Column(nullable = false)
private String name;
#ManyToOne(targetEntity = Address.class, cascade=CascadeType.PERSIST)
private Address address;
public Student(LocalDateTime registrationDateTime, String name, Address address) {
setRegistrationDateTime(registrationDateTime);
setName(name);
setAddress(address);
}
public Student() {
}
// ...getters and setters omitted...
}
and:
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String street;
public Address(String street) {
setStreet(street);
}
public Address() {
}
// ...getters and setters omitted...
}
When you execute the following code both entity are persisted but street is NULL.
Student student = new Student(LocalDateTime.now(), "John Doe");
student.setAddress(new Address("Mainstreet"));
studentRepository.save(student);
When I remove the #Id annotation from the LocalDateTime property and add the following code then the address is saved correctly.
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
These are the queries which Hibernate executes (it seems odd by the way that it's inserting the student first since that entity needs the id of the address).
Hibernate:
alter table Student
drop constraint FKf12myy73nsf6soln9xli8th80
Hibernate:
drop table Address
Hibernate:
drop table Student
Hibernate:
drop sequence hibernate_sequence restrict
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
create table Address (
id integer not null,
street varchar(255),
primary key (id)
)
Hibernate:
create table Student (
dateTime timestamp not null,
name varchar(255) not null,
address_id integer,
primary key (dateTime)
)
Hibernate:
alter table Student
add constraint FKf12myy73nsf6soln9xli8th80
foreign key (address_id)
references Address
Hibernate:
select
student0_.dateTime as dateTime1_3_0_,
student0_.address_id as address_3_3_0_,
student0_.name as name2_3_0_
from
Student student0_
where
student0_.dateTime=?
Hibernate:
values
next value for hibernate_sequence
Hibernate:
insert
into
Student
(address_id, name, dateTime)
values
(?, ?, ?)
Hibernate:
insert
into
Address
(street, id)
values
(?, ?)
Hibernate:
update
Student
set
address_id=?,
name=?
where
dateTime=?

JPA/HIbernate integrity constraint violated on cascade

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);

How to avoid insert and update queries in one-to-many uni-directional association

I have a simple one-to-many relationship between Employee & Phone entities.
I have 2 issues here.
Scenario 1 :
#Entity
public class Employee {
#Id
#GeneratedValue
private long id;
private String firstName;
private String lastName;
private double salary;
#OneToMany
#JoinColumn(name = "parent_id", referencedColumnName = "id", insertable=false, updatable=false)
private List<Phone> phones = new ArrayList<Phone>(0);
// Setters & Getter methods
}
Phone.java
#Entity
public class Phone {
#Id
private long id;
private String type;
private int areaCode;
private String phoneNumber;
// Setter & Getters
}
Now I created employee instance and added 2 phones to it.
Employee e1 = new Employee(10,"Bob", "Way",50000);
Phone p1 = new Phone(1,"home",613,"792-0000");
Phone p2 = new Phone(2,"work",613,"896-1234");
e1.addPhone(p1);
e1.addPhone(p2);
Then in hibernate, if I use below code:
session.save(e1);
session.save(p1);
session.save(p2);
or if I save phone then employee
session.save(p1);
session.save(p2);
session.save(e1);
In both cases, Hibernate just runs insert queries with out any update queries but the foreign key is set to NULL.
mysql> select * from Phone;
+----+----------+-------------+------+-----------+
| id | areaCode | phoneNumber | type | parent_id |
+----+----------+-------------+------+-----------+
| 1 | 613 | 792-0000 | home | NULL |
| 2 | 613 | 896-1234 | work | NULL |
| 3 | 416 | 123-4444 | work | NULL |
+----+----------+-------------+------+-----------+
How can I fix this? Please let me know where I made mistake.
Scenario 2 :
Now if I made change to my #JoinColumn in Employee table like below:
#JoinColumn(name = "parent_id")
Then Hibernate is generating **insert** then update queries to map the foreign key properly.
Hibernate: insert into Employee (firstName, lastName, salary) values (?, ?, ?)
Hibernate: insert into Phone (areaCode, phoneNumber, type, id) values (?, ?, ?, ?)
Hibernate: insert into Phone (areaCode, phoneNumber, type, id) values (?, ?, ?, ?)
Hibernate: insert into Phone (areaCode, phoneNumber, type, id) values (?, ?, ?, ?)
Hibernate: update Phone set parent_id=? where id=?
Hibernate: update Phone set parent_id=? where id=?
When Hibernate runs the insert on Employee table then it gets the employee id there itself, then why does Hibernate runs additional update query when it can just run a single insert query on Phone table by including the foreign key value?
I understand that in update query it is adding the foreign key, but I would like to know why this is not managed in insert query itself on Phone table. Can you please explain this?
Scenario 3:
If I say like this:
#JoinColumn(name = "OWNER_ID", insertable=false, updatable=false, nullable=false)
Then I get below exception:
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value : onetomany.Phone._phones_OWNER_IDBackref
You have a Employee and an Phone.
You'd like to add insertable=false, updatable=false to the #OneToMany relationship with the Employee entity in the Phone entity, simply because it's not the responsibility of the Phone entity to create or update a Employee. It's the other way round.
#Entity
public class Employee {
#Id
#GeneratedValue
private long id;
private String firstName;
private String lastName;
private double salary;
#OneToMany(mappedBy="person", cascade=CascadeType.ALL)
private List<Phone> phones = new ArrayList<Phone>(0);
// Setters & Getter methods
}
#Entity
public class Phone {
#Id
private long id;
private String type;
private int areaCode;
private String phoneNumber;
#ManyToOne
#JoinColumn(name="PHONE_FK")
#Column(insertable=false, updatable=false)
private Employee employee;
}

JPA OneToMany bi-directional

I know that there is many question about it but i can not find a good answered for my problem .
I am using Jboss as 7, Spring and Hibernate (4) as JPA 2.0 provider so i have got simple #OneToMany bi-directional relationship :
I have got super class person like that:
#MappedSuperclass
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class Person {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(min = 1, max = 25)
#Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces")
private String name;
public Person(String name) {
super();
this.name = name;
}
And class Member:
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = "email"))
public class Member extends Person implements Serializable
{
/** Default value included to remove warning. Remove or modify at will. **/
private static final long serialVersionUID = 1L;
#NotNull
#NotEmpty
#Email
private String email;
#NotNull
#Size(min = 10, max = 12)
#Digits(fraction = 0, integer = 12)
#Column(name = "phone_number")
private String phoneNumber;
#OneToMany(cascade=CascadeType.ALL , mappedBy="member" , fetch=FetchType.EAGER)
private List<Order> orders;
And also class Order:
#Entity
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private float price;
#ManyToOne(optional=false)
private Member member;
private String name;
So i think that it is a good configuration, but i test this application in HSQL in memory and i have got error :
Hibernate: alter table Order drop constraint FK48E972E548C740B
2012-09-20 16:25:37 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: HHH000389: Unsuccessful: alter table Order drop constraint FK48E972E548C740B
2012-09-20 16:25:37 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: Blad skladniowy w wyrazeniu SQL "ALTER TABLE ORDER[*] DROP CONSTRAINT FK48E972E548C740B "; oczekiwano "identifier"
Syntax error in SQL statement "ALTER TABLE ORDER[*] DROP CONSTRAINT FK48E972E548C740B "; expected "identifier"; SQL statement:
alter table Order drop constraint FK48E972E548C740B [42001-165]
And also :
Syntax error in SQL statement "CREATE TABLE ORDER[*] (ID INTEGER GENERATED BY DEFAULT AS IDENTITY, NAME VARCHAR(255), PRICE FLOAT NOT NULL, MEMBER_ID BIGINT NOT NULL, PRIMARY KEY (ID)) "; expected "identifier"; SQL statement:
And my JUnit test failed i dont know what is wrong with this configuration ...
this is my simply junit :
#Test
public void testInsertWithOrder(){
Order order = new Order(20.0f, "first stuff");
Order order2 = new Order(40.0f, "secondary stuff");
List<Order> orders = new ArrayList<Order>();
orders.add(order2);
orders.add(order);
Member member = new Member("Member name", "member23#gmail.com", "2125552141", orders);
memberDao.register(member);
List<Member> members = memberDao.findAllOrderedByName();
Assert.assertNotNull(members);
Assert.assertEquals(1, members.size());
}
Change table name from 'order' to something different, like PersonOrder
In your member in Order Class, there are missing #JoinColumn annotation. Try as below.
#ManyToOne(optional=false)
#JoinColumn(name = "memberId", referencedColumnName = "id")
private Member member;
#CycDemo
I am just figure it out and in my constuctor i now have got :
#OneToMany(cascade=CascadeType.ALL , mappedBy="member" , fetch=FetchType.EAGER)
private List<UOrder> orders = new ArrayList<UOrder>();
public Member(String name, String email, String phoneNumber ,List<UOrder> orders) {
super(name);
this.orders = orders;
this.email = email;
for(UOrder o : orders){
o.setMember(this);
}
this.orders = orders;
}
Ant this is it what i need :)))

Categories

Resources