Spring + hibernate one to one mapping - spring

I am developing web application using spring and hibernate. I am using one to one mapping between two tables employee and PersonelDetails.
below are my bean classes
=======================Employee=====================================
#Entity
#Table(name="employee")
public class Employee {
#Id
#Column
#GeneratedValue
private int empid;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
#Column
private String password;
#Column
private boolean isAdmin;
#Column
private boolean isActive;
#Column
private boolean isLocked;
//getter setters
====================PersonalDetails class====================
#Entity
#Table(name="PersonalDetails")
public class PersonalDetails {
#Column
#Id
private int empid;
#Column
private String personalEmail;
#Column
private String mob;
#Column
private String permenantAdress;
#Column
private String currentAddress;
#Column
private String gender;
#Column
private String maritialStatus;
#MapsId
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "empid", referencedColumnName = "empid")
#ForeignKey(name="empid")
private Employee employee;
//getter setters
In my application table employee is filled by Admin user while creating new employee after that employyee himself fill personalDetails table by login to his accountCreated by Admin)
Now when I try to send personal details bean to hibernate layer first I have to get the employee bean from employee table then call setEmployee method over personalDetails class and save employee bean in personalDetails and send to hibernate layer for saving in database.
So while getting employee bean from database and again send back through personalDetails bean leads to a performance issue.
Can anyone help here to clarify while saving data in child table(PersonalDetails) is it really mandatory to pass parent object(Employee) ?
=======================code to store personalDetails===============
#RequestMapping(value="addpersonal")
public ModelAndView addPersonalDetails(#ModelAttribute("personalDetails") PersonalDetails personalDetails) {
//personalDetails.setEmpid(1);
personalDetails.setCurrentAddress("niljyoti");
personalDetails.setMob("9405715872");
personalDetails.setPermenantAdress("address");
Employee e = empService.getEmployeebyUserName(uname);
personalDetails.setEmployee(e);
personalDetailsService.addPersonalDetails(personalDetails);
return new ModelAndView("home");
}

On read:
You can change fetch strategy if you are worried.
Based od JPA spec, default fetch type for #OneToOne is EAGER.
By setting fetch = FetchType.LAZY, instead of real PersonalDetails object, an object of a subclass behaving as a proxy is returned. Hence, selecting from employee table starts only after getEmployee is called.
On write:
You need to specify connection between entities, in your model, the only way is the employee field. However, you can specify mappedBy, see answer to this question:
Java: Hibernate #OneToOne mapping

Related

Composite primary key and ManyToOne hibernate

I'm learning Hibernate and I'm trying to make the Mapping work. My entities are as follows
Department:
#Entity
public class Department {
#Id
#GeneratedValue
private Integer id;
private String name;
private String hqLocation;
// getters and setters omitted for brevity
}
WorkerId:
#Embeddable
public class WorkerId implements Serializable {
private Integer workerId;
private Integer deptId;
// getters and setters omitted for brevity
}
Worker:
#Entity
public class Worker {
#EmbeddedId
private WorkerId id;
private String name;
private Integer age;
// How to make #ManyToOne mapping work?
private Department department;
// getters and setters omitted for brevity
}
Question: How to make #ManyToOne on the field private Department department; work? Simply adding the annotation results private Department department; as null.
I think you want to use a "derived identity"; so you should make Worker.department like this:
#Entity
public class Worker {
#EmbeddedId
private WorkerId id;
private String name;
private Integer age;
#MapsId("deptId")
#ManyToOne // <<<< edit
private Department department;
// getters and setters omitted for brevity
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
Question really is, which entity should be the owner of the relationship? would you like to map bidirectional or single way?
Here is the bidirectional example
#OneToMany(
fetch = FetchType.EAGER,
mappedBy = "department",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Worker> workers;
#JoinColumn(name = "department_id", nullable = false)
#ManyToOne(targetEntity = Department.class, fetch = FetchType.LAZY)
private Department department;
fetch types are optional and depend on the use case

join table and get data based on field value JPA

I have two entities
#Entity
public class Module {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String descr;
#OneToMany(cascade = {CascadeType.ALL})
#JoinColumn(name="ID", referencedColumnName="ID")
private List<Permissions> perms;
}
#Entity
public class Permissions {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private Integer clientId;
private String role;
private Character endorseCreate;
private Character endorseUpdate;
private Character endorseDelete;
private Character endorseView;
I am trying to fetch data by first Module.name and Permissions.clientId and Permissions.role
Something like in sql
select * from Module m, Permissions p where m.id=p.id and p.clientId=1 and p.role='ADMIN'
How can I achieve using JPA, I am using spring data aswell.
Can a method be declared in CRUD Repo provided by spring data?
I think the issue is I am unable to find way to pass values to fetch data.
Any help is greatly appreciated

Spring boot entities,relationships and repository confusion

I am confused as to how relationships work in entities and what this means with regard to my JPA repository.
I have a class called Loan which stores a list of albums for each loan.
I have a loan repository and an album repository. The album repository is filled with albums when I start the application. The albumId is autogenerated.
When I create a new loan and try to add an album from the repository I get an exception :
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.library.demo.entity.Album; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.library.demo.entity.Album
If I create a new loan and add a new album on the fly then it works as expected. During the debug I realised that this is because albumId is null when adding a new album on the fly to the loan, presumably because it adds the album to the repository and generates a new albumId when the loan is created.
My album entity looks like this :
#Entity
public class Album implements Serializable {
private static final long serialVersionUID = 0x63A6DA99AA12AAA8L;
#Column #GeneratedValue(strategy = GenerationType.AUTO) #Id private Integer albumId;
#Column (unique=true) private String barcode;
#Column private String band;
#Column private String title;
#Column private String genre;
#Column private Integer year;
#Column private String artworkFilename;
#Column private Boolean enabled;
#Column private Boolean isLoanable;
#Column private Integer numberOfCopies;
#ManyToOne
private Loan loan;
And my loan looks like this :
public class Loan implements Serializable {
private static final long serialVersionUID = 0x62B6DA99AA12AAA8L;
public void setLoanId(Integer loanId) {
this.loanId = loanId;
}
#Column #GeneratedValue(strategy = GenerationType.AUTO) #Id private Integer loanId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Album> albums= new ArrayList<>();
#Column private Integer customerId;
#Column private Date dateLoaned;
#Column private Date dateToReturn;
#Column private Boolean expired;
I am also confused as to why the album has to refer back to the loan with a ManyToOne annotation. Why does the album have to refer to the loan?
I am mostly used to relation databases so maybe I am thinking about things in the wrong way. If I can only add new albums to the loan then it defeats the purpose of what I am trying to do.
Loan and Album tables have a one-to-many relationship.
So in Album your mapping should be like below:
#ManyToOne
#JoinColumn(name = "loan_id")
private Loan loan;
Considering loan_id is the primary key of Loan.
And in Loan your mapping should be like below:
#OneToMany(mappedBy = "loan", cascade = CascadeType.ALL)
private List<Album> albums;
#OneToMany and #ManyToOne defines a one-to-many and many-to-one relationship between 2 entities. #JoinColumn indicates the entity is the owner of the relationship: the corresponding table has a column with a foreign key to the referenced table. mappedBy indicates the entity is the inverse of the relationship
I have updated my source as you have described and made some changes to the start up.
If I create the loan first and then save it to the loan repository and add the album set afterwards, it no longer crashes.
Loan loan = new Loan(1, new Date(), calendar.getTime(),null);
loanRepository.save(loan);
List<Album> albumList = AlbumImport.getAlbumList();
albumRepository.save(albumList);
List<Album> albums = new ArrayList<>();
albums.add(albumList.get(1));
albums.add(albumList.get(5));
loan.setAlbums(albums);
However, when I run my getLoan test the album list is empty
Removing cascade = CascadeType.ALL fixed my problem.

Spring MVC + Hibernate one to one mapping

I am trying to develop an application using spring mvc and hibernate.
I have following entity classes
Employee
EmployeePeronellDetails
EmployeeSallaryDetails
EmployeeProfesionalDetails
I have an integer employeeID as a primary key in employee table which further acts as foreign key in other three tables
I have created 4 different forms to fill information to above tables.
4 forms opened one after the other
How my entity classes should look like?
I followed few tutorials they suggested to create Employee class object in other classes.
So after successfully inserting data in employee table. Do I need to save respective Employee object in session?
After this while creating EmployeePeronellDetails bean pass that session's employee object to EmployeePeronellDetails's setter method/constructor.
Below are my employee and EmployeePeronellDetails classes
#Entity
#Table(name="employee")
public class Employee {
#Id
#Column
#GeneratedValue
private int empid;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
#Column
private String password;
#Column
private boolean isAdmin;
#Column
private boolean isActive;
#Column
private boolean isLocked;
//geter setters
========================PersonalDetails class===========================
#Entity
#Table(name="PersonalDetails")
public class PersonalDetails {
#Column
#Id
private int empId;
#Column
private String personalEmail;
#Column
private String mob;
#Column
private String permenantAdress;
#Column
private String currentAddress;
#Column
private String gender;
#Column
private String maritialStatus;
#OneToOne
#JoinColumn(name="empid")
private Employee employee;
Now when I tried to call sessionFactory.getCurrentSession().saveOrUpdate(personalDetails);
It gives
org.hibernate.TransactionException: nested transactions not supported]
Exception.

Spring and Hibernate Error -- not-null property references a null or transient value: com.tharaka.model.Employee.designation

im new to Spring and hibernate, i got the error above when trying to persist the transaction data. please try to help this problem
Here's my Entity:
#Entity #NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e")
public class Employee implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String city;
private String civil;
#Temporal(TemporalType.DATE)
#Column(name="dob", length=11)
private Date dob;
private String email;
private int epf;
private String fname;
private String gender;
private int landtp;
private String lname;
#Temporal(TemporalType.DATE)
#Column(name="salaryincrement", length=11)
//bi-directional many-to-one association to Designation
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="designation_id", nullable=false)
private Designation designation;
public Employee() { }
#Entity
#NamedQuery(name="Designation.findAll", query="SELECT d FROM Designation d")
public class Designation implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String type;
//bi-directional many-to-one association to Employee
#OneToMany(mappedBy="designation")//, cascade=CascadeType.ALL
private List<Employee> employees;
public Designation() {
}
this is my Entity class,
Entities have a getters ans setters
designation is set nullable = false. However employees variable isn't initialized in Designation. So, you'll have to initialize as
#OneToMany(mappedBy="designation")//, cascade=CascadeType.ALL
private List<Employee> employees = new LinkedList<>();
I'm not sure that you can go with primitive type int as your Id - you should probably use Integer - because int has default zero value and cannot be null, your new record can be rather seen as a detached entity with Id ZERO and not as a transient one.
The same mistake is in Designation class.
See Primitive or wrapper for hibernate primary keys

Resources