I am very new to hibernate and I am working with JPA and Hibernate4. Trying to insert parent object in child as onetoone relationship.
I went through some tutorials but All the example in the web shows, inserting both parent and child tables.
I want to insert data in child table only.
I have two tables called user and department.
User table consists of user details with department as onetoone relationship, as follows,
#Entity
#Table(name = "User")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentId")
private Department departmentId;
// getters and setters...
}
Below is my Department entity,
#Entity
#Table(name = "Department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "name")
private String name;
// getters and setters...
}
In department table there is only 4 data. I want to insert data only in user data while insert into it and don't want to insert in Department.
How can I do that.Please assist.
You have to use mappedBy for this, as mentoned below in child Table, Department in your case
#OneToOne(mappedBy="department")
private UserEntity user;
These posts explain you better this,
JPA JoinColumn vs mappedBy
Understanding mappedBy annotation in Hibernate
You need to specify the relationship owner using mappedBy property in the OneToOne mapping in the owner side, here in your case in the Department class, you should add:
#OneToOne(mappedBy="department")
private UserEntity user;
I updated your code, to included the stated annotation and also renamed the Department property in your UserEntity class from departmentId to department to avoid confusion between relationship owner and its id:
#Entity
#Table(name = "User")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentId")
private Department department;
// getters and setters...
}
Below is the Department entity,
#Entity
#Table(name = "Department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "name")
private String name;
#OneToOne(mappedBy="department")
private UserEntity user;
// getters and setters...
}
This will give you the right mapping with the expected behaviour.
In the #OneToOne annotation, the default value for parameter optional is true. So your annotation is the same as #OneToOne(fetch = FetchType.EAGER, optional = true). This means you can simply leave the Department in a UserEntity instance empty. In that case, persisting it results in persisting only a user entity and no department.
Even if you created a Department instance and assigned it to a UserEntity instance, persisting the UserEntity would not automatically persist the Department, since you don't have any cascade parameter in your annotation. If you don't automatically cascade persists, you would have to persist the Department first and then persist the corresponding user entity.
Maybe you're asking about using existing departments for your user entities. In that case, you first need to get the department via Hibernate (or the JPA API) from an entity manager. The entity instance you get is managed by Hibernate, and you can then set it in a UserEntity and persist that, to have it refer to the department.
Finally, I think one department will probably have more than one user. It might make more sense to have a #ManyToOne annotation instead of #OneToOne, indicating multiple users can refer to the same department, but that depends on your domain model.
Related
I'm developing one simple app where where I have an one entity class class Employee. And now I want to create/copy new similar entity called ActiveEmployees from existing Employee. I want to add functionality that If I hit the new api endpoint ->POST: http://locahost:8080/api/employee/active/john -> So, it should save existing Employee John Record in the new table active_employees with the all Table data.
#Entity
#Table(name="employee")
public class Employee{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column
#NotNull
private String firstNname;
#Column
#NotNull
private String lastNname;
#Column
#NotNull
private String department;
#JsonManagedReference
#OneToOne(fetch = FetchType.LAZY,
mappedBy = "employee",
cascade = CascadeType.ALL,
orphanRemoval = true)
ActiveEmployee activeEmployee;
... Constructor, getters and setters
}
#Entity
#Table(name="active_employees")
public class ActiveEmployees {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonBackReference
#OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id")
private Employee employee;
}
I think you should use inheritance mapping in hibernate instead having two table with same fields. There are multiple strategies. Check and use best one which fits your requirement.
Read the tutorial here https://www.javatpoint.com/hibernate-inheritance-mapping-tutorial
You can use inhertiance with #MappedSuperclass. But if I will design this application I will add boolean field "active" to Employee class.
I have an employee who can work in multiple departments. I have OneToMany relashionship in Employee and ManyToOne in the Department class.
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Size(min = 3, max = 10, message = "Invalid name")
private String name;
#Email
private String email;
#OneToMany(mappedBy = "employee")
private List<Department> departments;
}
#Entity
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String department;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id", referencedColumnName = "id")
private Employee employee;
}
The created tables in MySQL looks like the following:
The employees table:
The departments table:
The problem is that I will have multiple employees and they can have multiple departments. The departments table will be too large and the departments name will be repeated for the different employees as you can see in the picture above I have 2xManagement. My question is if it is possible to create the departments table without the employee_id (only to have the departments name) and do the linking in a separate table with only two properties - employee_id and department_id. Do I need to create a new class for that? How can I optimize this relashionship? Is there a way to do it?
You need change solution to #ManyToMany by using weak entity,
References: https://www.baeldung.com/hibernate-many-to-many
I have 3 tables which are Person Login and Account.
Person and Login is OneToOne relation and Login has one FK which is connected Person's id column called PERSON_ID.
Person(one) and Account(many) is OneToMany relation and Account has one FK which is connected Person's id column called PERSON_ID as well .
what i want to do is when i delete one data from Account , nothing happen to Person and Login.
if i delete one data from Person which id=1, Login's PERSON_ID=1 data will be deleted , and all of the data PERSON_ID=1 from Account will be deleted as well.
if i delete one data from Login which PERSON_ID=1, Person 's id=1 data will be deleted , and all of the data PERSON_ID=1 from Account will be deleted as well.
how should i set the cascade ?
i've tried dozens of times and still can't find the logic in there, thanks!!
here's my code of all 3 tables without setting cascade:
`
#Entity
#Table(name = "PERSON")
public class Person {
#Id
#Column(name = "ID", nullable = false, unique = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "NAME")
private String name;
#Column(name = "SEX")
private String sex;
#OneToMany(mappedBy = "person",fetch = FetchType.LAZY)
private List<Account> account;
#OneToOne(mappedBy = "person")
private Login login;
#get..
#set..
}
`
#Entity
#Table(name = "ACCOUNT")
public class Account {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "ACCOUNT")
private String account;
#Column(name = "AMOUNT")
private String amount;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERSON_ID",referencedColumnName = "ID")
public Person person;
#get..
#set..
}
`
#Entity
#Table(name = "LOGIN")
public class Login {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private long id;
#Column(name = "USERNAME")
private String userName;
#Column(name = "PASSWORD")
private String password;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERSON_ID", referencedColumnName = "ID")
private Person person;
#get..
#set..
}
It's been a while, but if I'm not mistaken you need to use the cascade=REMOVE option on the OneToMany and OneToOne relationships. In the OneToOne I think you need to specify cascade=REMOVE on the side that does NOT own the relationship, that is, the side that also contains the "mappedBy" property.
Finally, I believe JPA will NOT automatically load lazy relationships and then cascade them. I'm thinking you may need to fetch the relationship before you delete the parent entity (otherwise JPA will not know what to delete).
So i'm learning from these simple examples, there're 2 tables, USERS and USER_DETAILS, simple enough, each user has user_details and it's 1-to-1 relationship. So this sample is like this,
#Entity
#Table(name = "USERS")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_ID")
private long id;
#Column(name = "USERNAME", nullable = false, unique = true)
private String username;
#Column(name = "PASSWORD")
private String password;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
private UserDetail userDetail;
//Setter and getter methods
}
#Entity
#Table(name = "USER_DETAILS")
public class UserDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_DET_ID")
private long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "EMAIL")
private String email;
#Column(name = "DBO")
private LocalDate dob;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "USR_ID")
private User user;
//Setter and Getter methods
}
If you look at mappedBy, it's in the User not UserDetails.
Q1: so USER is the owner, if it calls save(),
USER_DETAILS table will be updated as well ?
Q2: same examples put mappedBy in the USER_DETAILS side,
why people want to do this ?
How to determine which side to put mappedBy ?
Thanks for your help !
Q2: same examples put mappedBy in the USER_DETAILS side,
why people want to do this ?
How to determine which side to put mappedBy ?
In a bidirectional relationship, each entity has a relationship field
or property that refers to the other entity. Through the relationship
field or property, an entity class’s code can access its related
object. If an entity has a related field, the entity is said to “know”
about its related object.
There is a bidirectional one-to-one relationship in your example. Both User and UserDetail entities have a relationship field. #OneToOne annotation specified on both the entities.
For one-to-one bidirectional relationships, the owning side
corresponds to the side that contains the corresponding foreign key.
The owner of the relationship is UserDetail entity. The owner has #JoinColumn annotation to specify foreign key (USR_ID).
Inverse side of relationship (User) has mappedBy attribute.
Q1: so USER is the owner, if it calls save(),
USER_DETAILS table will be updated as well ?
In your example UserDetail is the owner. Therefore the saving process:
User user = new User(); // Ignoring the constructor parameters...
UserDetail userDetail = new UserDetail();
user.setUserDetail(userDetail);
userDetail.setUser(user);
userRepository.save(user);
You only need to save the parent. It will save the child as well.
I have a datamodel, which has:
a User entity which has a few fields specific to 2 users in the application
another entity UserDetails, which contains details specific to one particular type of user in the application besides the fields in User entity
Both entities share the same primary key. I am new to JPA. What kind of mappings should be there between the two?
#Entity
class User{
#Id
#Column(name="USER_ID")
private int id;
}
#Entity
class UserDetails{
#Id
#OneToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_ID")
private User user;
...
}
The above mapping gives issues on fetching UserDetails for a particular User.
It requires that both Entities share the same primary key USER_ID.
You didn't mention the issues with the above mapping. It looks OK, but I would use a separate primary key for UserDetails table.
#Entity
class UserDetails{
#Id
private int id;
#OneToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_ID")
private User user;
...
}
Also, it is a good practise to use bidirectional relationships, for eaiser navigation i.e. getting user details from User, you would just use user.getUserDetails(); so in User class:
#Entity
class User{
#Id
#Column(name="USER_ID")
private int id;
#OneToOne(mappedBy = "user")
private UserDetails userDetails;
}
In this case use OneToOne relationship. But make sure your database table UserDetailshas foreign key relationship to User table. Use below code to implement it using JPA and Hibernate.
#Entity
class User{
#Id
#Column(name="USER_ID")
private int id;
// getters and setters
}
#Entity
class UserDetails{
#Id
#Column(name="USER_DETAILS_ID")
private int userDetailsId;
#OneToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID")
private User user;
// getters and setters
}