Foreign key in hibernate - java

I have two simple tables Customers and Orders with relation oneToMany from customer to Orders table.
This is my Customers.java
#Entity
public class Customers implements Serializable {
#Id
#GeneratedValue
private int cID;
private String name;
private String email;
// getter and setters
}
And this is Orders.java:
#Entity
public class Orders implements Serializable {
#Id
#GeneratedValue
private int orderID;
private int cId;
#Column(nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne(cascade = CascadeType.ALL)
private Customers customers;
// getter and setters
}
Now, i am going to insert two record in Orders table:
public static void main(String[] args) {
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Orders orders1 = new Orders();
Orders orders2 = new Orders();
Customers customer = new Customers();
customer.setName("c1");
customer.setEmail("abc#gmail.com");
orders1.setDate(new Date());
orders2.setDate(new Date());
orders1.setCustomers(customer);
orders2.setCustomers(customer);
session.save(orders1);
session.save(orders2);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
This is the result in console:
Hibernate: alter table Orders drop foreign key FK_hmbx2rg9tsgqikb3kodqp90c4
Hibernate: drop table if exists Customers
Hibernate: drop table if exists Orders
Hibernate: create table Customers (cID integer not null auto_increment, email varchar(255), name varchar(255), primary key (cID))
Hibernate: create table Orders (orderID integer not null auto_increment, cId integer not null, date date not null, customers_cID integer, primary key (orderID))
Hibernate: alter table Orders add constraint FK_hmbx2rg9tsgqikb3kodqp90c4 foreign key (customers_cID) references Customers (cID)
Feb 24, 2015 1:58:52 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into Customers (email, name) values (?, ?)
Hibernate: insert into Orders (cId, customers_cID, date) values (?, ?, ?)
Hibernate: insert into Orders (cId, customers_cID, date) values (?, ?, ?)
And this is the result tables:
Why the cID in Orders table (which is a foreign key references to customers) is 0?
It should be 1.

It think in your orders table customers_cId is the actual foreign key reference column to the customers table. As you haven't gave any column name explicitly, it internally took column name as customers_cId by joining the variables from both the entities. customers from the orders and cId from the customers entity.
Just to verify you can try giving some other name using #JoinColumn annotation.
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="order_cId")
private Customers customers;
And cId in orders table is just one more independent column, as you have not set any value to it, its taking the default value as 0. Try setting some random value to it.

Related

Columns forming composite key in one table are actually in other table as foreign key-write entity class

Industry_Codes Table
Industry_Code(Primary key) | Industry_name
1| Reliance
2| TaTa
Technology_codes Table
Technology_code(Primary Key) | technology name
81| java
81|cpp
carrier_codes Table
Industry_Code(Primary key)(Foreign Key to Industry_Codes table) | technology_code(pk)(Foreign key to Technology_Code table) | other fields
1 | 81 |
2| 81|
1| 82
Register
Mobile Number(Pk)|Industry_code(Fk to carrier_codes) |Technology_Code(Fk to carrier_codes)
12345|1|83
78913|1|88
for the given table structure the entity class are written as-
#Entity
#Table(name = "Industry_Codes")
public class IndustryCodes implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="TELECOM_INDUSTRY_CODE")
private String telecomIndustryCode;
#Column(name="INdustry_Name")
private String Industry_Name;
}
Table 2
#Entity
#Table(name="Technology_Codes")
public class TechnologyCodes {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "Technology_code")
private int targetTechnologyCode;
#Column(name="Technology_Name")
private String TechnologyName;
}
and
#Entity
#Table(name = "CARRIER_CODES")
public class CarrierCodes {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name ="CARRIER_CODE",referencedColumnName="INDUSTRY_CODE")
private IndustryCodes carrierCode;
#Id
#ManyToOne
#JoinColumn(name ="TECHNOLOGY_CODE",referencedColumnName="TECHNOLOGY_CODE")
private TechnologyCodes TechnologyCode;
}
Now I am all lost on how to write entity for Register table which has column like carrier_code and technology_code both of these are foreign key to carrier_codes table adn both of these together form composite key for carrier_codes table also there are many occurance of both field in both table thus a many to many association between both columns of both table.
Any help on writing the register entity is appreciated. I am completely new to associations in JPA.
First, be sure you understand the relationships. UML and images are your friend.
Notice that IndustryCode and TechCode is a ManyToMany relationship. In DDL a many to many relationship is done with join table and a composite key. In JPA this is normally just mapped with a ManyToMany annotation but since you also want to use it as a foreign key for the Registry table you must define the entity yourself. This is done with CarrierCodes. In JPA an EmbeddableId is generally the easiest way to make a composite key for an entity that will be used in this manner. So the JPA can be done like this:
#Entity
public class IndustryCode {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String industryName;
#OneToMany(mappedBy="industryCode")
private Set<CarrierCodes> industryCodes;
#Entity
public class TechCode {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String techName;
#OneToMany(mappedBy="techCode")
private Set<CarrierCodes> techCodes;
#Entity
public class CarrierCodes {
#EmbeddedId
private CarrierCodesId id = new CarrierCodesId();
#ManyToOne
#MapsId("techCodeId")
private TechCode techCode;
#ManyToOne
#MapsId("industryCodeId")
private IndustryCode industryCode;
#SuppressWarnings("serial")
#Embeddable
public class CarrierCodesId implements Serializable {
private Long industryCodeId;
private Long techCodeId;
#Entity
public class Register {
#Id
private Long mobileNumber;
#ManyToOne
// optional but nice to have consistent names
#JoinColumns({
#JoinColumn(name="industryCode_id", referencedColumnName="industryCode_id"),
#JoinColumn(name="techCode_id", referencedColumnName="techCode_id")
})
private CarrierCodes carrierCodes;
And to use it similar to your example is like this.
tx.begin();
IndustryCode ic1 = new IndustryCode("Reliance");
IndustryCode ic2 = new IndustryCode("TaTa");
TechCode tc1 = new TechCode("java");
TechCode tc2 = new TechCode("cpp");
CarrierCodes cc1 = new CarrierCodes(tc1, ic1);
CarrierCodes cc2 = new CarrierCodes(tc1, ic2);
CarrierCodes cc3 = new CarrierCodes(tc2, ic1);
Register r1 = new Register(12345L, cc1);
Register r2 = new Register(78913L, cc2);
em.persist(ic1);
em.persist(ic2);
em.persist(tc1);
em.persist(tc2);
em.persist(cc1);
em.persist(cc2);
em.persist(cc3);
em.persist(r1);
em.persist(r2);
tx.commit();
em.clear();
List<Register> rs = em.createQuery("select r from Register r left outer join fetch r.carrierCodes cc where cc.techCode.techName = 'java'", Register.class).getResultList();
rs.stream().forEach(r->System.out.println(r.getMobileNumber() + " " + r.getCarrierCodes().getTechCode().getTechName()));
List<Register> rs2 = em.createQuery("select r from Register r left outer join fetch r.carrierCodes cc where cc.industryCode.industryName = 'TaTa'", Register.class).getResultList();
rs2.stream().forEach(r->System.out.println(r.getMobileNumber() + " " + r.getCarrierCodes().getIndustryCode().getIndustryName()));
That gives me the following output.
Hibernate: create table CarrierCodes (industryCode_id bigint not null, techCode_id bigint not null, primary key (industryCode_id, techCode_id))
Hibernate: create table IndustryCode (id bigint generated by default as identity (start with 1), industryName varchar(255), primary key (id))
Hibernate: create table Register (mobileNumber bigint not null, industryCode_id bigint, techCode_id bigint, primary key (mobileNumber))
Hibernate: create table TechCode (id bigint generated by default as identity (start with 1), techName varchar(255), primary key (id))
Hibernate: alter table CarrierCodes add constraint FKfq42ix66txvd15crq2pey3dcp foreign key (industryCode_id) references IndustryCode
Hibernate: alter table CarrierCodes add constraint FK9os97pd53ijerp2mibllknovn foreign key (techCode_id) references TechCode
Hibernate: alter table Register add constraint FK2k626ouo1ajsccqlpb5y3xa8u foreign key (industryCode_id, techCode_id) references CarrierCodes
Hibernate: insert into IndustryCode (id, industryName) values (default, ?)
Hibernate: insert into IndustryCode (id, industryName) values (default, ?)
Hibernate: insert into TechCode (id, techName) values (default, ?)
Hibernate: insert into TechCode (id, techName) values (default, ?)
Hibernate: insert into CarrierCodes (industryCode_id, techCode_id) values (?, ?)
Hibernate: insert into CarrierCodes (industryCode_id, techCode_id) values (?, ?)
Hibernate: insert into CarrierCodes (industryCode_id, techCode_id) values (?, ?)
Hibernate: insert into Register (industryCode_id, techCode_id, mobileNumber) values (?, ?, ?)
Hibernate: insert into Register (industryCode_id, techCode_id, mobileNumber) values (?, ?, ?)
Hibernate: select register0_.mobileNumber as mobileNu1_2_0_, carriercod1_.industryCode_id as industry1_0_1_, carriercod1_.techCode_id as techCode2_0_1_, register0_.industryCode_id as industry2_2_0_, register0_.techCode_id as techCode3_2_0_ from Register register0_ left outer join CarrierCodes carriercod1_ on register0_.industryCode_id=carriercod1_.industryCode_id and register0_.techCode_id=carriercod1_.techCode_id cross join TechCode techcode2_ where carriercod1_.techCode_id=techcode2_.id and techcode2_.techName='java'
Hibernate: select industryco0_.id as id1_1_0_, industryco0_.industryName as industry2_1_0_ from IndustryCode industryco0_ where industryco0_.id=?
Hibernate: select techcode0_.id as id1_3_0_, techcode0_.techName as techName2_3_0_ from TechCode techcode0_ where techcode0_.id=?
Hibernate: select industryco0_.id as id1_1_0_, industryco0_.industryName as industry2_1_0_ from IndustryCode industryco0_ where industryco0_.id=?
12345 java
78913 java
Hibernate: select register0_.mobileNumber as mobileNu1_2_0_, carriercod1_.industryCode_id as industry1_0_1_, carriercod1_.techCode_id as techCode2_0_1_, register0_.industryCode_id as industry2_2_0_, register0_.techCode_id as techCode3_2_0_ from Register register0_ left outer join CarrierCodes carriercod1_ on register0_.industryCode_id=carriercod1_.industryCode_id and register0_.techCode_id=carriercod1_.techCode_id cross join IndustryCode industryco2_ where carriercod1_.industryCode_id=industryco2_.id and industryco2_.industryName='TaTa'
78913 TaTa

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?

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=?

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 (?, ?, ?)

Understanding annotations and JPA(hibernate)

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.

Categories

Resources