I am developing a spring boot application, i need a proper design help for one of my entity relation.
These are my tables
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
User_ID INT AUTO_INCREMENT PRIMARY KEY,
Email VARCHAR(1024),
Phone BIGINT,
Password VARCHAR(128),
User_Type ENUM ('TEACHER', 'PARENT'),
Status ENUM ('ACTIVE', 'DEACTIVE', 'SUSPENDED')
);
DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher
(
Teacher_ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(1024),
Email VARCHAR(1024),
Phone BIGINT,
Gender ENUM (0, 1),
Date_Of_Joining INT,
Designation VARCHAR(1024),
Is_Active INT
);
DROP TABLE IF EXISTS parent;
CREATE TABLE parent
(
Parent_ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(1024),
Email VARCHAR(1024),
Phone BIGINT,
Occupation VARCHAR(1024),
Address VARCHAR(4048)
);
DROP TABLE IF EXISTS student;
CREATE TABLE student
(
Student_ID INT AUTO_INCREMENT PRIMARY KEY,
Student_Name VARCHAR(1024),
Class VARCHAR(16),
Section VARCHAR(16),
Academic_Year VARCHAR(64),
DOB DATE,
Gender ENUM (0, 1),
Parent_ID INT
);
Can anyone please help me creating entity classes for the same. Based on the type of user in user table i need to join with either teacher or parent table. For example if User_Type is TEACHER then i will join with teacher table else i will join user with parent table. Join condition would be email.
Student table has one to one relationship with parent table.
You can create domain models like this
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
public User{
//properties
}
#Entity
#PrimaryKeyJoinColumn(name = "id")
public Teacher extends User{
//properties
}
#Entity
public Parent extends User{
//properties
}
#Entity
public Students {
#GenericGenerator(name = "generator", strategy = "foreign",parameters = #Parameter(name = "property", value = "stock"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "Parent_ID", unique = true, nullable = false)
private Integer id;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
public Parent parent;
}
You can use the following classes:
User:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
#Table(name = "user")
public class User {
#Id
#GeneratedValue
#Column(name = "User_ID")
private Integer userID;
#Column(name = "name", length = 1024)
private String name;
#Column(name = "email", length = 1024)
private String email;
#Column(name = "Phone")
private Long phone;
#Column(name = "Password", length = 128)
private String password;
#Column(name = "User_Type", columnDefinition = "enum ('TEACHER', 'PARENT')")
private String userType;
#Column(name = "Status", columnDefinition = "enum ('ACTIVE', 'DEACTIVE', 'SUSPENDED')")
private String status;
}
Teacher:
#Entity
#Table(name = "teacher")
public class Teacher extends User{
#Id
#GeneratedValue
#Column(name = "teacher_ID")
private Integer teacherID;
#Column(name = "name", length = 1024)
private String name;
#Column(name = "email", length = 1024)
private String email;
#Column(name = "Phone")
private Long phone;
#Column(name = "Gender", columnDefinition = "BOOLEAN")
private Boolean gender;
#Column(name = "Date_Of_Joining")
private Integer dateOfJoining;
#Column(name = "Designation", length = 1024)
private String designation;
#Column(name = "Is_Active")
private Integer isActive;
}
Parent:
#Entity
#Table(name = "parent")
public class Parent extends User{
#Id
#GeneratedValue
#Column(name = "Parent_ID")
private Integer parentID;
#Column(name = "name", length = 1024)
private String name;
#Column(name = "email", length = 1024)
private String email;
#Column(name = "Phone")
private Long phone;
#Column(name = "Occupation", length = 1024)
private String occupation;
#Column(name = "Address",length=4048)
private String address;
}
Student:
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue
#Column(name = "Student_ID")
private Integer studentID;
#Column(name = "student_name", length = 1024)
private String studentName;
#Column(name = "study_class", length = 16)
private String studyClass;
#Column(name = "section", length = 16)
private String section;
#Column(name = "academic_year",length = 64)
private String academicYear;
#Temporal(TemporalType.DATE)
#Column(name = "dob", length = 4048)
private Date dob;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn(name = "parent")
public Parent parent;
}
Try them out and see if that helps.
Related
I have 2 tables Employee and Address. Each have primary key empId and addressId which is generated through sequence.
Employee Class:
public class Employee {
#Id
#Column(name = "sequence_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_seq")
#SequenceGenerator(sequenceName = "emp_seq", allocationSize = 1, name = "emp_seq")
private Long sequenceId;
#Column(name = "emp_id")
private String empId;
#Column(name = "joiningDate")
private Date businessDate;
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
private Address address;
}
Address Class
public class Address {
#Id
#Column(name = "address_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "address_seq")
#SequenceGenerator(sequenceName = "address_seq", allocationSize = 1, name = "address_seq")
private Long addressID;
#Column(name = "street")
private String street;
#OneToOne
#JoinColumn(name = "emp_id")
#JsonIgnore
private Employee employee;
}
I am using JPARepository to save both entities. here is my main class.
Employee e = Employee.builder().businessDate(new Date())
.empId("thinkerId").build();
Address a = Address.builder().street("32nd Street")
.employee(e).build();
e.setAddress(a);
empRepository.save(e);
Code runs successfully. But in my Address table, emp_Id column contains the primary key instead of the emp_id column.
How can i get "thinkerId" as value in Address table?
Thank you.
In Address entity you must explicitly specify the column you are referring to:
public class Address {
#Id
#Column(name = "address_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "address_seq")
#SequenceGenerator(sequenceName = "address_seq", allocationSize = 1, name = "address_seq")
private Long addressID;
#Column(name = "street")
private String street;
#OneToOne
#JoinColumn(name = "emp_id", referencedColumnName = "emp_id")
#JsonIgnore
private Employee employee;
}
Using Hibernate, I have created two entities - Employee and EmployeeDetails. Since EmployeeDetails cannot exist without a corresponding entry in Employee, I figured I don't need an extra ID for EmployeeDetails, but could instead use the ID of the Employee entity. Here is how I have implemented this idea:
Employee-Entity:
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToOne(cascade = CascadeType.ALL)
EmployeeDetails employeeDetails;
}
Employee-Details-Entity:
#Entity
#Table(name = "employee_details")
#Data
public class EmployeeDetails {
#Id
private Long id;
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
#MapsId
#OneToOne(mappedBy = "employeeDetails", cascade = CascadeType.ALL)
#JoinColumn(name = "employee_id")
private Employee employee;
}
By adding the #MapsId annotation to the employee-variable inside EmployeeDetails, I should be assigning the primary key of the Employee-entity to the Id-column of EmployeeDetails.
In a second step, I have written some data into both of my tables.
employee table in MySQL database:
employee_id first_name last_name employee_details_employee_id
1 John Smith null
2 Jennifer Adams null
The last column was somehow generated by Hibernate. I don't understand why. It appears to be some column for identification, but I don't need it.
employee_details table in MySQL database:
employee_id address e_mail phone
1 null john.smith#gmail.com null
2 null jennifer.adams#gmail.com null
I have only assigned an e-mail to the employees. Surprisingly, there is no employee-entry in this database table. I don't really need it anyways, but I was expecting it. So yeah, I think I am doing something terribly wrong and would really appreciate some help.
Change mappedBy side, here useful links
https://vladmihalcea.com/change-one-to-one-primary-key-column-jpa-hibernate/
https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
https://javabydeveloper.com/one-one-bidirectional-association/
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
EmployeeDetails employeeDetails;
}
Entity
#Table(name = "employee_details")
#Data
public class EmployeeDetails {
#Id
private Long id;
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
#MapsId
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "employee_id")
private Employee employee;
}
#MapId is not a popular solution in work with Hibernate.
Maybe in your case, #Embeddable will be a better option?
If I understand correctly, EmployeeDetails cannot exist without correlated Employee. So, EmployeeDetails could be a field in Employee as an embeddable field:
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#Embedded
EmployeeDetails employeeDetails;
}
Then EmployeeDetails doesn't need ID and relation with the employee:
#Embeddable
public class EmployeeDetails {
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
}
As you can see, now in the database it's only one table employees, but in our hibernate model, we have two separated objects. Probably you don't need EmployeeDetails without Employee entity, so there is more efficient construction.
If you really need a separated table for EmployeeDetails with relation to Employee I recommend creating standard one-to-one mapping instead of #MapId construction.
When I run this code, it is running with out error. But When I check the values, as you can see, In the "Tbl_InstructorDetail" table the parentId is null
can anyone help.
thank you.
This is my Entities and my main class with table relation
enter image description here
this is my tables from my database
create table Tbl_Instructor
(
uuid int identity
constraint Pk_Tbl_Instructor_uuid
primary key,
Title nvarchar(50)
)
create table Tbl_InstructorDetail
(
uuid int identity
constraint Pk_Tbl_InstructorDetail_uuid
primary key,
Created_By nvarchar(50),
parentId int
constraint Fk_Tbl_InstructorDetail_Tbl_Instructor
references Tbl_Instructor
)
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
#Basic
#Column(name = "parentId", nullable = true,insertable = false,updatable = false)
private Integer parentId;
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
Main class
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
instructor.setDetailEntity(detail);
session.getTransaction().begin();
session.save(instructor);
session.getTransaction().commit();
You don't need to add parentId in TblInstructorDetailEntity because it's referenced from TblInstructorEntity. In main class foreign key pass null because you can take a reference to the parent table before save parent table.
Here down is modified code:
Entity
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
// remove parentId column because it is foreign key
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
// getter setter
}
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
// getter setter
}
Main
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
session.save(instructor); // Save parent entity
detail.setInstructorEntity(instructor); // Reference from parent entity
session.save(detail); // Save child entity
session.getTransaction().commit();
HibernateUtil.shutdown();
I have an issue related with that JPA enity not saved in database, so
after added new clob field in jpa entity - entity doesn't save in database
I use websphere, spring 4.3.13 and Oracle11g
my jpa enity before
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.Audited;
import javax.persistence.*;
import java.sql.Timestamp;
#Entity
#Audited
#Table(name = "UserRecord")
#NoArgsConstructor(access = AccessLevel.PUBLIC)
#AllArgsConstructor
#Getter
#Setter
#Access(AccessType.FIELD)
public class UserRecord {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PR_KEY")
private String prKey;
//Business Key
#Column(name = "businessId", length = 100, unique = false)
private String businessId;
//Business Key
#Column(name = "name", length = 100, nullable = false)
private String name;
//Business Key
#Column(name = "surname", length = 100, nullable = false)
private String surname;
#Column(name = "updateDateTime", length = 50, nullable = false)
private Timestamp updateDateTime;
#Version
private int version;
#Column(name = "user", length = 100000)
#Lob
private byte[] user;
public UserRecord(String businessId, String name, String surname, Timestamp updateDateTime, byte[] user) {
this.businessId = businessId;
this.name = name;
this.surname = surname;
this.updateDateTime = updateDateTime;
this.user = user;
}
}
and after
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.Audited;
import javax.persistence.*;
import java.sql.Timestamp;
#Entity
#Audited
#Table(name = "UserRecord")
#NoArgsConstructor(access = AccessLevel.PUBLIC)
#AllArgsConstructor
#Getter
#Setter
#Access(AccessType.FIELD)
public class UserRecord {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PR_KEY")
private String prKey;
//Business Key
#Column(name = "businessId", length = 100, unique = false)
private String businessId;
//Business Key
#Column(name = "name", length = 100, nullable = false)
private String name;
//Business Key
#Column(name = "surname", length = 100, nullable = false)
private String surname;
#Column(name = "updateDateTime", length = 50, nullable = false)
private Timestamp updateDateTime;
#Version
private int version;
#Column(name = "user", length = 100000)
#Lob
private byte[] user;
#Column(name = "userXml")
#Lob
private String userXml;
public UserRecord(String businessId, String name, String surname, Timestamp updateDateTime, byte[] user, String userXml) {
this.businessId = businessId;
this.name = name;
this.surname = surname;
this.updateDateTime = updateDateTime;
this.user = user;
this.userXml = userXml;
}
}
serice layer code fragment is
before
record = new RiskMetricRecord(businessId, name, surname, updateDateTimeTimestamp, serialize(userToSave));
after
record = new RiskMetricRecord(businessId, name, surname, updateDateTimeTimestamp, serialize(userToSave), userToSave);
And my Jparepository is:
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface UserRepository extends CrudRepository<UserRecord, String> {
}
So, when I try to save my entity in database after added field #Lob String in JPA entity - there is no error messages, but, in database there is no changes too..
More info:
database table is
-- auto-generated definition
CREATE TABLE USERRECORD
(
PR_KEY VARCHAR2(255 CHAR) NOT NULL
PRIMARY KEY,
BUSINESSID VARCHAR2(100 CHAR),
USER BLOB,
NAME VARCHAR2(100 CHAR) NOT NULL,
SURNAME VARCHAR2(100 CHAR) NOT NULL,
VERSION NUMBER(10) NOT NULL,
UPDATEDATETIME TIMESTAMP(3),
USERXML CLOB
)
/
Tried:
1)
#Lob
#Column(name = "userXml", columnDefinition = "CLOB")
private String userXml;
When I worked on persisting BLOB in app, I tried byte[], it did not save the data. Then I changed data type of property in my entity class to java.sql.Blob, which fixed the problem.
In your case, you are working with CLOB, then change data type of properties from String or byte[] to java.sql.Clob.
#Column(name = "user", length = 100000)
#Lob
private Clob user;
#Column(name = "userXml")
#Lob
private Clob userXml;
So before your persist entity, you have to transform payload of user and userXml properties to Clob objects.
To create Clob object, you can use Hibernate utilities.
Hibernate.getLobCreator(getHibernateSession()).createClob(stringvar);
in JPA, you can easily use TEXT property as mentioned here, it will store any amount of data. Also, no need to define length manually. And also delete #Lob, there is no need. Keep in mind that first delete your column at DB and re-create to update its definition.
#Column(name = "userXml", columnDefinition="TEXT")
private String userXml;
I had tables like Customer, Request and so on and each had ID field;
I have now an abstract
#MappedSuperclass instead that have
#Id
#GeneratedValue
private Long id
field, and all tables extends it with
#AttributeOverride(name="id", column=#Column(name="ID_CUSTOMER"). but now, when I'm trying to add customer to a table, I'm getting exception: Column ID_Customer cannot accept Null value.
when each table had it's own id fields, all works fine.
what's wrong?
Thanks
#MappedSuperclass
public abstract class GeneralEntity implements Serializable,Cloneable{
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#Column(name = "CREATED",nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date created;
#Column(name = "MODIFIED")
#Temporal(TemporalType.TIMESTAMP)
private Date modified;
//getters,setters
#Entity
#Table(name = "CUSTOMER")
#AttributeOverrides({
#AttributeOverride(name = "id", column = #Column(name="ID_CUSTOMER")),
#AttributeOverride(name="created", column=#Column(name="CUSTOMER_REGISTERED",nullable = false))
})
public class Customer extends GeneralEntity{
// #Column(name = "ID_CUSTOMER")
// #Id
// #GeneratedValue
// private Long id;
#Column(name = "CUSTOMER_EMAIL", nullable = false, length = 25, unique = true, updatable = true)
private String email;
#Column(name="CUSTOMER_PASSWORD", nullable = false)
private String password;
//getters setters