Create and populate child table from Parent table using Hibernate Annotation - java

I need to create a table EMPLOYEE_REMARK from a table EMPLOYEE.
And need to do it with Annotation Hibernate.
EMPLOYEE
EMP_ID, EMP_FNAME, EMP_LNAME
EMPLOYEE_REMARK
EMP_REMARK_ID, EMP_ID, REMARK
it will be a OnetoOne relationship i.e, for each EMP_ID there will be one REMARK. REMARK could be null.
please help me with the solution...
Can it be done by creating one class from employee and populate the EMPLOYEE_REMARK from it???

Basically here is the way of doing what you want.
Employee
#Entity
#Table(name = "EMPLOYEE")
public class Employee implements Serializable {
#Id
#Column(name = "EMP_ID")
private Long id;
#Column(name = "EMP_FNAME")
private String firstName;
#Column(name = "EMP_LNAME")
private String lastName;
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL,
orphanRemoval = true)
private EmployeeRemark employeeRemark;
public void setRemark(String remark) {
this.employeeRemark = new EmployeeRemark();
this.employeeRemark.setRemark(remark);
this.employeeRemark.setEmployee(this);
}
public String getRemark() {
return employeeRemark == null ? null : employeeRemark.getRemark();
}
//getters and setters
}
Employee Remark
#Entity
#Table(name = "EMPLOYEE_REMARK")
public class EmployeeRemark implements Serializable {
#Id
#Column(name = "EMP_REMARK_ID")
private Long id;
#OneToOne
#JoinColumn(name = "EMP_ID")
private Employee employee;
#Column(name = "REMARK")
private String remark;
//getters and setters
}
When saving employee, just call save on employee. EmployeeRemark will cascade to all operations and will be removed along with employee or if it become an orphan in other way.

Related

OneToOne mapping JPA - Cascade.All not copying the id column

I tried searching for this specific issue but could not get any help
While creating Employee --> Account should get created.
My entities are --> Employee entity
#Entity
#Table(name = "EMPLOYEE")
public class EMPLOYEE implements Serializable {
private static final long serialVersionUID = -1798070786993154676L;
#Id
#Column(name = "EMPLOYEE_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int EMPLOYEE_id;
#Column(name = "EMPLOYEE_name")
private String EMPLOYEE_name;
#Column(name = "EMPLOYEE_desc")
private String EMPLOYEE_desc;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "EMPLOYEE_id")
#MapsId
private ACCOUNT account;
// getters and setters
}
account entity -->
#Entity
#Table(name = "ACCOUNT")
public class ACCOUNT implements Serializable {
private static final long serialVersionUID = -6790693372846798580L;
#OneToOne( fetch = FetchType.LAZY)
#JoinColumn(name = "EMPLOYEE_id")
private EMPLOYEE employee
#Id
#Column(name = "account_id")
private int account_id;
#Column(name = "account_desc")
private String account_desc;
// getters setters
}
While creating Employee --> Account should get created.
My pojo is getting mapped correctly as shown below -->
employee = { EMPLOYEE_id = 0 ,
EMPLOYEE_name = 'abc' ,
EMPLOYEE_desc = 'new employee' ,
account = { account_id = 1 ,
account_desc = 'my account' ,
EMPLOYEE_id = 0 }
}
so when i same employee object - it generates employee_id , but the same employee_id is not getting populated in account table
It is partly working --> in the Account table Employee_id is not getting populated.
I tried searching so many questions on stackOverflw - but no luck so far.
Any help is appreciated.
Thank you in advance
If the #OneToOne is defined on both sides of the relationship, one side should be the owner. That is the entity that has the foreign key. The other side should have the mappedBy attribute. So the following works for me
#Entity
#Table(name = "EMPLOYEE")
public class EMPLOYEE implements Serializable {
#OneToOne(cascade= CascadeType.ALL, mappedBy = "employee") // non-owner side
private Account account;
....
}
#Entity
#Table(name = "ACCOUNT")
public class Account implements Serializable {
#OneToOne( fetch = FetchType.LAZY)
#JoinColumn(name = "EMPLOYEE_id") // owner-side
private Employee employee;
}

Null values are inserted in the foreign key fields with Hibernate

I have a Question Entity and Tag entity with getter, setter methods and a OneToMany relationship from question to tag and a OneToOne relationship from question to user
public class Question {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name="title")
private String title;
#Column(name="body")
private String body;
#Temporal(TemporalType.DATE)
#Column(name="date_created")
private Date date_created;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="user_id")
private User user;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="tag_id")
private Tag tag;
#Column(name="answer_count")
private int answer_count;
#Column(name="view_count")
private int view_count;
public Question() {
}
Tag entity
public class Tag {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#Column(name="username")
private String username;
#Temporal(TemporalType.DATE)
#Column(name="date_created")
private Date date_created;
public Tag() {
}
When I try to insert a question using Postman with the following details:
{
"title": "stefanyyyxx",
"body": "stefandoyee44",
"date_created": "2019-02-27",
"user_id" : 1,
"tag_id": 1,
"answer_count": 0,
"view_count": 0
}
QuestionRepository.java:
#Override
public void save(Question theQuestion) {
// get the current hibernate session
Session currentSession = entityManager.unwrap(Session.class);
// save employee
currentSession.saveOrUpdate(theQuestion);
}
Null values are being inserted for user_id and tag_id though I used JoinColumn().
MySQL:
As #Karol Dowbecki Suggested,
convert the JSON to DTO object and use that DTO to get the User, Tag Entities from their respective repositories.
Finally create the Question entity object and store it.
Question Entity
#Entity
#Table(name = "question")
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "title")
private String title;
#Column(name = "body")
private String body;
#Temporal(TemporalType.DATE)
#Column(name = "date_created")
private Date dateCreated;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "tag_id")
private Set<Tag> tag;
#Column(name = "answer_count")
private int answerCount;
#Column(name = "view_count")
private int viewCount;
}
User Entity
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
Tag Entity
#Entity
#Table(name = "tag")
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "username")
private String username;
#Temporal(TemporalType.DATE)
#Column(name = "date_created")
private Date dateCreated;
}
DTO Class
public class QuestionDTO {
private Long id;
private String title;
private String body;
private Date dateCreated;
private Long user;
private Long tag;
private int answerCount;
private int viewCount;
}
Test Class
#Service
public class TestService {
#Autowired
private QuestionRepository questionRepository;
#Autowired
private UserRepository userRepository;
#Autowired
private TagRepository tagRepository;
public void addQuestion(QuestionDTO dto) {
Tag tag = null;
User user = null;
Question question = null;
Set<Tag> tags = null;
tag = tagRepository.findById(dto.getTag());
tags = new HashSet<>();
tags.add(tag);
user = userRepository.findById(dto.getUser());
question = new Question();
question.setTag(tags);
question.setUser(user);
question.setId(dto.getId());
question.setBody(dto.getBody());
question.setTitle(dto.getTitle());
question.setViewCount(dto.getViewCount());
question.setAnswerCount(dto.getAnswerCount());
question.setDateCreated(dto.getDateCreated());
questionRepository.save(question);
}
}
NOTE :
The relation between Question and Tag are in OneToMany you have to use Collection type.
You have a mismatch between JSON and #Entity structure. JSON contains numeric identifiers while the #Entity contains actual objects representing relationships. You most likely should introduce a separate DTO class to map this JSON while in #Repository you should load User and Tag objects based on their id or create new ones. You already have CascadeType.ALL so Hibernate will cascade the persist operation.
Generally the controller layer should be separate from repository layer unless you are doing something very, very simple. This helps to evolve the service without changing the API contract e.g. adding new columns for auditing changes. By exposing the #Entity as DTO you make your life harder down the road.
You should add referencedColumnName in your Child Entity Foreign Key Column
referencedColumnName="your primaray key column name"
EDIT:
referencedColumnName
The name of the column referenced by this foreign key column.
When used with entity relationship mappings other than the cases
described here, the referenced column is in the table of the target
entity.
When used with a unidirectional OneToMany foreign key mapping, the
referenced column is in the table of the source entity.
When used inside a JoinTable annotation, the referenced key column is
in the entity table of the owning entity, or inverse entity if the
join is part of the inverse join definition.
When used in a CollectionTable mapping, the referenced column is in
the table of the entity containing the collection.
Default (only applies if single join column is being used): The same
name as the primary key column of the referenced table.
Asset is Parent Entity and AssetDetails is Child Entity
Here I have taken OneToOne Relationship
Asset.java
#Entity
#Table(name="asset")
public class Asset {
#Id
#GeneratedValue
#Column(name="assetid")
private BigInteger assetid;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "asset")
#JsonBackReference
private AssetDetails assetDetails;
public AssetDetails getAssetDetails() {
return assetDetails;
}
public void setAssetDetails(AssetDetails assetDetails) {
this.assetDetails = assetDetails;
assetDetails.setAsset(this);
}
public Asset(your fields, AssetDetails assetDetails) {
super();
// your fields
this.assetDetails = assetDetails;
this.assetDetails.setAsset(this);
}
public Asset() {
super();
}
public BigInteger getAssetid() {
return assetid;
}
public void setAssetid(BigInteger assetid) {
this.assetid = assetid;
}
}
AssetDetails.java
#Entity
#Table(name="assetDetails")
public class AssetDetails {
#Id
#GeneratedValue
private BigInteger assetdetailid;
#JoinColumn(name = "assetid",nullable = false, updatable = false,referencedColumnName="assetid")
#OneToOne(cascade=CascadeType.ALL)
#JsonManagedReference
private Asset asset;
public Asset getAsset() {
return asset;
}
public void setAsset(Asset asset) {
this.asset = asset;
}
public AssetDetails(your fields,Asset asset) {
super();
//your fields
this.asset = asset;
}
}

Spring data JPA save updating parent entity

Student.java
#Entity
#Table(name = "Student")
#Data
#NoArgsConstructor
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "studentId", cascade = CascadeType.ALL)
private List<Subject> subjectList = new ArrayList<>();
public void addSubject(Subject subject) {
subjectList.add(subject);
subject.setStudentId(this);
}
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
}
Subject.java
#Entity
#Table(name = "Subject")
#Data
#NoArgsConstructor
public class Subject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="studentId", nullable = false)
private Student studentId;
#Column(name = "subjectName")
private String subjectName;
#Column(name = "subjectCode")
private int subjectCode;
}
SubjectRepository.java
#Repository
public interface SubjectRepository extends JpaRepository<Subject, Long> {
}
As shown in the code structure above, I have 2 entities (Student, Subject) and a repository class (SubjectRepository). When i try to save into the Subject table, somehow the student name "Thomas" from the Student table gets updated as well in the database. I would like to only insert into Subject table without having any values from the Student table getting updated. Need some help on this. Thanks!
public static void main(String[] args) {
#Autowired protected SubjectRepository subjectRepository;
Student student = new Student();
student.setFirstName("Thomas");
Subject subject = new Subject();
subject.setSubjectName("Chemistry");
subject.setSubjectCode(12345);
student.addSubject(subject)
subjectRepository.save(subject)
}
I would like to only insert into Subject table without having any values from the Student table getting updated
You can achieve this with following code :
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="studentId", nullable = false, updatable = false)
private Student studentId;
When using Spring JPA I would suggest using the JpaRepository API. You just need to pass in your entity, and it should save as desired.
Ex:
subjectRepository.save(subject);
You have try this
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name="studentId", nullable = false, updatable = false)
private Student studentId;
#MaxExplode You have to use cascade = CascadeType.REFRESH then other details will not update. but if you are try to set updateStudent.setfirstNamr(student.getFirstName()); and then save parent object then i will update. otherwise it will not update.

Lazy load "JOINED" collection

I have the entity following entities:
Employee extends Person
Company has List<Employee> (lazy load).
When I try to initialize the employee list with Hibernate.initialize(company.getEmployees()); I receive an error since hibernate doesn't understand that Employee is a Person.
Person.java
#Entity
#Table(name = "person")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Person implements java.io.Serializable {
#Column(name = "person_id")
protected Long personId;
#Column(name = "name")
protected String name;
#Column(name = "age")
protected String age;
}
Employee.java
#Entity
#Table(name = "employee")
#PrimaryKeyJoinColumn(name = "person_id")
public class Employee extends Person {
#Column(name = "employee_number")
private String number;
#ManyToOne
#JoinColumn(name = "company_id")
private Company company;
}
Company.java
#Entity
#Table(name = "company")
public class Company implements java.io.Serializable {
#Column(name = "company_id")
protected String id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "company", cascade = CascadeType.ALL)
#OrderBy(clause = "name desc")
protected List<Employee> employees = new ArrayList<Employee>();
}
Hibernate.initialize(company.getEmployees());
Exception:
org.postgresql.util.PSQLException: ERROR: column employee0_.name does not exist
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
Is there any solution with lazy load for this case?
There is certainly one to one relationship between Employee and Person. It makes sense by splitting the objects in Java but not in terms of table. I think Employee table should have a name and other columns defined in person table to simplify the design.

Composite key joins in hibernate in java

I am using hibernate to persist two tables,Project and Department.
Department table has a composite primary key DeptCompID.
#Embeddable
public class DeptCompID implements Serializable
{
#Column(name = "DeptID")
private int DeptID;
#Column(name = "RoleID")
private int RoleID;
//getters and setters
}
#Entity
public class Department implements Serializable
{
#EmbeddedId
private DeptCompID id;
private String name;
#OneToOne(mappedBy="department",targetEntity = Project.class)
private Project pro;
//getters and setters
}
#Entity
public class Project
{
#Id
private int ProId;
#OneToOne(targetEntity = Department.class)
#MapsId("DeptID")
#JoinColumns({
#JoinColumn(name = "RoleID", referencedColumnName = "RoleID"),
#JoinColumn(name = "DeptID", referencedColumnName = "DeptID")
})
private Department department;
//getters and setters
}
Code to persist the tables
Department department = new Department();
department.setName("HR");
DeptCompID cpk=new DeptCompID();
cpk.setRoleID(10);
cpk.setDeptID(60);
department.setId(cpk);
Project pro=new Project();
pro.setDepartment(department);
pro.setProId(10);
department.setPro(pro);
session.save(department);
session.save(pro);
Everytime I persist the tables Project and Department the DeptID column in Project table is always null when it should be 60.
why is #MapsId("DeptID") not working?Could some provide a resolution.

Categories

Resources