I have two entities having parent child relationship - Person and Address.
They have a one-to-one relationship.
I am able to cascade save both of them by one save.
But the below code does not add a foreign_key address_id to Person table.
SQL:
create table PERSON (
id number(20) NOT NULL ,
PRIMARY KEY (id)
);
alter table Person add address_id number(20);
alter table Person add CONSTRAINT FK_Address FOREIGN KEY (address_id) REFERENCES address (id);
create table Address (
id number(20) NOT NULL ,
PRIMARY KEY (id)
);
Hibernate code:
#Entity
#Table(name="Person")
#javax.persistence.SequenceGenerator(name="SOME_SEQ", sequenceName="pk_sequence")
public class Person
{
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE, generator="SOME_SEQ")
private int id;
#OneToOne
#PrimaryKeyJoinColumn
#Fetch(FetchMode.JOIN)
#Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
private Address address;
}
#Entity
#javax.persistence.SequenceGenerator(name="SOME_SEQ", sequenceName="pk_sequence")
public class Address
{
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE, generator="SOME_SEQ")
private int id;
#Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
#OneToOne(mappedBy="address")
#Fetch(FetchMode.JOIN)
private Person person;
}
Driving code:
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Person p = new Person();
Address add = new Address ();
p.setAddress(add);
add.setPerson(p);
id = (Integer) session.save(p);
tx.commit();
Your mapping is wrong. You have a column in Person that is a foreign key to the address table. But you map the association with #PrimaryKeyJoinColumn, which means: The ID of this entity is also a foreign key to the address table. Use #JoinColumn. Not #PrimaryKeyJoinColumn.
Related
table: emps
(
id int primary key,
name varchar(50)
);
table: emps_sal
(
emps_sal_id int primary key auto_increment,
ids int,
salary int,
foreign key(ids) references emps(id)
);
Entity Classes:
#Entity
public class Emps {
#Id
#Column(name="id")
int id;
String name;
#OneToOne(mappedBy = "e")
Emps_sal esal;
--
}
#Entity
public class Emps_sal {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
int emps_sal_id;
int ids ;
int salary;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn(name="ids")
Emps e;
--
}
Now when I am doing simple select query its working fine. But when I am trying to add entry its working weirdly:
Emps e=new Emps();
e.setId(100);
e.setName("Johnson");
Emps_sal es=new Emps_sal();
es.setIds(100);
es.setSalary(5000);
es.setE(e);
e.setEsal(es);
Firstly in "emps" table it added a extra column "esal_emps_sal_id".
Though it added "100,Johnson" properly. But in Emps_sal nothing is
added. I was expecting "7, 100, 5000".
Change CascadeType to persist in Emps_sal entity class
#OneToOne(cascade = CascadeType.PERSIST)
#PrimaryKeyJoinColumn(name="ids")
Emps e;
The persist operation makes a transient instance persistent. CascadeType PERSIST propagates the persist operation from a parent to a child entity. When we save the Emps_sal entity, the Emp entity will also get saved.
Here is how you need to set the data
Emps e=new Emps();
e.setId(100);
e.setName("Johnson");
Emps_sal es=new Emps_sal();
es.setIds(100);
es.setSalary(5000);
es.setE(e);
entityManager.persist(es);
I want to store Persons with their Cars in the database. I use Spring 5.
The problem is that when I want to add a person with cars in the database, the 'person_id' field from the 'car' table is set to null instead of being set on the id of the created person.
That is weird because I even set that nullable=false in Car class.
#Entity
public class Person {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
#OneToMany(mappedBy = "person",cascade = CascadeType.ALL)
List<Car> cars;
}
#Entity
public class Car {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer carId;
#ManyToOne
#JoinColumn(name = "person_id",nullable=false)
private Person person;
}
CREATE TABLE person (
id INT PRIMARY KEY AUTO_INCREMENT,
...
);
CREATE TABLE car (
id INT PRIMARY KEY AUTO_INCREMENT,
person_id INT,
ADD CONSTRAINT person_id REFERENCES person(id)
);
I use the JpaRepository to save a person:
Person p = new Person();
List<Car> cars = new ArrayList<>();
Car c1 = new Car();
Car c2 = new Car();
cars.add(c1);
cars.add(c2);
p.setCars(cars);
personJpaRepository.save(p);
If you want to take advantage of the Cascade option you must remember to set the dependencies on both sides of the relationship.
Otherwise the persistence provider will not consider that as a relationship:
cars.add(c1);
cars.add(c2);
c1.setPerson(p);
c2.setPerson(p);
p.setCars(cars);
personJpaRepository.save(p);
I have the following relationship with person and transaction (one to one in my case). I want to be able to save a Person with a Transaction attached resulting in two inserts. One in tbl_person and one in tbl_Transaction. But the following only generates one insert instead of two. The one insert is in tbl_Transaction:
`CREATE TABLE `tbl_person` (
`ID` char(36) NOT NULL,
`TransactionID` int(11) DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `TransactionID` (`TransactionID`),
CONSTRAINT `tbl_person_ibfk_1` FOREIGN KEY (`TransactionID`)
REFERENCES `tbl_Transaction` (`TransactionID`)
);
CREATE TABLE `tbl_transaction` (
`TransactionID` int(11) NOT NULL,
PRIMARY KEY (`TransactionID`)
);
#Table(name="tbl_person")
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
#ToString
#Data
public class Person {
#Id
#GeneratedValue(generator = "hibernate-uuid")
#GenericGenerator(name = "hibernate-uuid", strategy = "uuid2")
#Column(name="ID", nullable = false)
private String ID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "transactionId")
private Transaction transaction;
}
#Table(name="tbl_transaction")
#Entity
#Data
public class Transaction {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer transactionId;
}
public class Service() {
public void saveTransaction(Transaction transaction) {
Person person = new Person();
person.setTransaction(transaction);
getSessionCurrent().save(person);
}
}
`
service.saveTransaction(transaction);
The service.saveTransaction returns with no exception but it only inserts the transaction but not the person.
Can any one tell me what I am doing wrong ??
you need to define a #OneToOne field in Transaction class
like specified in this question:
#OneToOne bidirectional mapping with #JoinColumn
and then add this line:
transcation.setPerson(person);
I'm new to Hibernate and I'm trying to establish a OneToMany/ManyToOne bidirectional relationship between Person and Vehicle classes. In my example a Person can have many Vehicles and a Vehicle belongs to only one Person. I need a join table: PERSON_VEHICLE with PERSON_ID and VEHICLE_ID as columns and a PERSON_ID column in VEHICLE table. Here's my class design:
Person class:
#Entity
public class Person {
#Id
#GeneratedValue
#Column(name = "PERSON_ID")
private int id;
private String name;
#OneToMany(cascade=CascadeType.ALL, mappedBy="person")
private Collection<Vehicle> vehicleList = new ArrayList<>();
Vehicle class:
#Entity
public class Vehicle {
#Id
#GeneratedValue
#Column(name = "VEHICLE_ID")
private int id;
private String name;
#ManyToOne
#JoinColumn(name="PERSON_ID")
#JoinTable(name="PERSON_VEHICLE", joinColumns=#JoinColumn(name="VEHICLE_ID"),
inverseJoinColumns=#JoinColumn(name="PERSON_ID"))
private Person person;
Here are the DDLs generated by Hibernate.
create table Person (
PERSON_ID integer not null auto_increment,
name varchar(255),
primary key (PERSON_ID)
)
create table Vehicle (
VEHICLE_ID integer not null auto_increment,
name varchar(255),
primary key (VEHICLE_ID)
)
create table PERSON_VEHICLE (
PERSON_ID integer,
VEHICLE_ID integer not null,
primary key (VEHICLE_ID)
)
alter table PERSON_VEHICLE
add index FK_h3d046x5uvbo53p8ms41hwqx (PERSON_ID),
add constraint FK_h3d046x5uvbo53p8ms41hwqx
foreign key (PERSON_ID)
references Person (PERSON_ID)
alter table PERSON_VEHICLE
add index FK_mtm2mn29hel3lbpl6i526w40v (VEHICLE_ID),
add constraint FK_mtm2mn29hel3lbpl6i526w40v
foreign key (VEHICLE_ID)
references Vehicle (VEHICLE_ID)
The VEHICLE table doesn't have PERSON_ID column. Something is wrong but I cannot find what the problem is.
Join table is not required for oneToMany relationship. Only two tables Person and Vehicle is sufficient for this mapping. For detailed example, see This Example
There is a structure. I want to link the three entities in this way: the Company should contain id, name of company and the list of Departments, each Department has a list of Workers, id and name of department. Each worker has name, id.
+Company
-int companyId
-String companyName
-Set<Department> listOfDepartments = new HashSet<Department>();
+Department
-int departmentId
-String departmentName
-Set<Worker> listOfWorkers = new HashSet<Worker>();
+Worker
-int workerId
-String workerName
I tried to make a connection with the one-to-many and many-to-one, but is not successful.
Сompany
#Entity
#Table(name="Company")
public class Company {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private int idCompany;
private String companyName;
#OneToMany(mappedBy = "company")
private Set<Department> listOfDepartments = new HashSet<Department>();
Department
#Entity
public class Department {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private int idDepartment;
private String departmentName;
#ManyToOne
#JoinColumn(name="idCompany")
private Company company;
#OneToMany(mappedBy = "department")
private Set<Worker> listOfWorkers = new HashSet<Worker>();
Worker
#Entity
public class Worker {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private int idWorker;
private String workerName;
#ManyToOne
#JoinColumn(name="idDepartment")
I start with:
Session session = sessionFactory.openSession();
session.beginTransaction();
Worker worker1 = new Worker("WorkerName1");
Worker worker2 = new Worker("WorkerName2");
Worker worker3 = new Worker("WorkerName3");
Worker worker4 = new Worker("WorkerName4");
Department department = new Department("Technical");
department.getListOfWorkers().add(worker1);
department.getListOfWorkers().add(worker2);
department.getListOfWorkers().add(worker3);
department.getListOfWorkers().add(worker4);
company = new Company("MyCompanyName");
company.getListOfDepartments().add(department);
session.save(company);
session.getTransaction().commit();
session.close();
It fills company, but not fills other tables and also it's not creating any joins(maps)
Error:
Hibernate: alter table Department drop foreign key FK_l7sg67atqhnn0soqynpvxrtpk
Hibernate: alter table Worker drop foreign key FK_s53hyohtyjy93srd2wkksairk
Hibernate: drop table if exists Company
Hibernate: drop table if exists Department
Hibernate: drop table if exists Worker
Hibernate: create table Company (idCompany integer not null auto_increment, companyName varchar(255), primary key (idCompany))
Hibernate: create table Department (idDepartment integer not null auto_increment, departmentName varchar(255), idCompany integer, primary key (idDepartment))
Hibernate: create table Worker (idWorker integer not null auto_increment, workerName varchar(255), idDepartment integer, primary key (idWorker))
Hibernate: alter table Department add index FK_l7sg67atqhnn0soqynpvxrtpk (idCompany), add constraint FK_l7sg67atqhnn0soqynpvxrtpk foreign key (idCompany) references Company (idCompany)
Hibernate: alter table Worker add index FK_s53hyohtyjy93srd2wkksairk (idDepartment), add constraint FK_s53hyohtyjy93srd2wkksairk foreign key (idDepartment) references Department (idDepartment)
ноя 11, 2013 3:10:31 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into Company (companyName) values (?)
In addition to the cascade mentioned in Glenn Lane's answer, you also need to understand how bidirectional associations work.
They have an owner side, and an inverse side. JPA only cares about the owner side to decide which association exists between entities. The owner side is the one which doesn't have the mappedBy attribute.
Your code add depertments to the company, and workers to the departments, but it only initializes the inverse sides. You forgot to initialize the owner side:
worker1.setDepartment(department);
worker2.setDepartment(department);
...
department.setCompany(company);
If you want JPA to automatically persist the children, you need to further decorate your #OneToMany:
#OneToMany(mappedBy = "department", cascade={CascadeType.PERSIST})
If you want cascading behaviour for other operations, like remove, merge, refresh, you'll need to add those to the cascade list as well.
You can use another approach:
Unidirectional OneToMany:
http://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Unidirectional_OneToMany.2C_No_Inverse_ManyToOne.2C_No_Join_Table_.28JPA_2.0_ONLY.29
You still need to persist the Object and then add it into your Collection.