Fetch specific property in hibernate One-to-many relationship - spring

I have two pojo classes with one-to-many relationship in hibernate
CustomerAccountEnduserOrderDetails.class
#Entity #Table(name="customer_account_enduser_order_details")
public class CustomerAccountEnduserOrderDetails implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "product_id", insertable = false, updatable = false)
private CustomerCmsProduct customerCmsProduct;
}
Second is CustomerCmsProduct.class
#Entity
#Table(name="customer_cms_product")
#JsonIgnoreProperties(ignoreUnknown = true)
public class CustomerCmsProduct {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private Long id;
#Column(name="name")
private String name;
#Column(name="offer_price")
private String offerPrice;
#Column(name="original_price")
private String originalPrice;
#Column(name="discount")
private String discount;
}
Here if I fetch the object of CustomerAccountEnduserOrderDetails class,then i will get the CustomerCmsProduct class also , my problem is that here i want the specific column of CustomerCmsProduct table (not all by default i am getting all) like only id and originalPrice.
How i can do like that projection here?

In the service layer or at a webservice layer( if this is a web project) Create two different classes other than #Entity as DTO(Data Transfer Objects) which helps is data transfer from one layer to the other.
public class CustomerAccountEnduserOrderDetailsPojo {
private List<CustomerCmsProductPojo> productPojoList = new ArrayList<> ();
// getter and setter
}
public class CustomerCmsProductPojo {}
Follow the below steps
Retrieve the #Entity class data by executing the query from service layer.
Iterate over all the fields and copy only required fields to pojo layer
Expose the data to other layers using service method.
This way, we can avoid changing the custom hibernate behavior as it is linked with many parameters like cache, one to many queries that are fired per iteration.
And also, do any customization that you want in this layer. Hope this is multi layered project where you have different layers which servers different purpose.

Related

How to generate an entity from another entity JPA - Spring boot

I have a spring boot JPA project with an entity called Customers and another one CustomerReports
#Entity
public class Customers {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
private String Name;
#JsonIgnore
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id", referencedColumnName = "id")
private Reports reports;
//getter and setters..etc
}
#Entity
public class CustomerReports {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
private BigDecimal monthlyPayment;
//done
#JsonIgnore
#OneToOne(mappedBy = "reports")
private Customers customers;
//constructors, getters...etc.
}
I want whenever I insert a Customer, a report to also be generated for that customer. The column "monthlyPayment" in reports is also generated through a reference from another table so I don't want to insert those columns manually if that makes sense.
Is there a way to do that? I'm not sure what to google so it would be great if anyone can give me an idea
If I understand your question properly, you can derive CustomerReports entity based on Customers via simple java utility method & then call save if you are using jparepository :
CustomerReports customerReports=reportUtil(customerEntity);
jpaRepository.save(customerEntity);
jpaRepository.save(customerReports);
...
private CustomerReports reportUtil(Customers customerEntity){
/*Derive values for CustomerReports based on Customers & return*/
}
Or if you don't want to do by this way then check if your underlying database support triggers which you can use for inserting data into CustomerReports while doing insert to Customers

Spring JPA bidirectional relation on multiple nested entities

I know there has been multiple questions on bidirectional relations using spring jpa in the past but my case is a little bit different because i am using 3 entities with 2 relationships to implement a medical system
I have 3 entities : doctor/patient/appointment
here is the code for the 3 entities
please note all setters , getters and constructors implemented but ommited here for clarity
Patient class
#Entity
public class resPatient {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String name;
private String gender;
private String email;
private String mobile;
private int age;
private String notes;
#OneToMany(mappedBy = "patient")
List<resPackageMembership> memberships;
#OneToMany(mappedBy = "patient")
List<resAppointment> appointments;
#OneToMany(fetch = FetchType.LAZY,mappedBy = "patient")
List<resMedImage> medImages;
Doctor class
#Entity
public class resDoctor {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String name;
private String mobile;
private String email;
private String gender;
private int age;
private String speciality;
#OneToMany(mappedBy = "doctor")
List<resAppointment> appointments;
Appointment class
#Entity
public class resAppointment {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String speciality;
#Basic
#Temporal(TemporalType.TIMESTAMP)
private Date dateCreated;
#Basic
#Temporal(TemporalType.TIMESTAMP)
private Date dateToVisit;
private String status;
private String notes;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "doctorCode")
private resDoctor doctor;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "patientCode")
private resPatient patient;
the way my medical system should work is that when i get a patient using my restful controller i want all the patient data including his appointments but this leads to an infinite loop as the appointment has the doctor which also has appointments and so on.
i cannot user #JSONIGNORE as there are 2 relationships i want to get the patient with his appointments which should have the doctor without the appointments array and should not have any patient data as i already am in the patient object
As a general best-practice, it's recommended to separate the entities from the data transfer objects used for the rest controllers. With DTO's in place, you have more control on which data to include and serialize within them to avoid the circlular references.
If you like check out https://bootify.io, it generates the DTOs from your database schema, but the custom endpoint you still need to define/build.
I develop an annotation processor called beanknife recently, it support generate DTO from any class. You need config by annotation. But you don't need change the original class. This library support configuring on a separate class. Of course you can choose which property you want and which you not need. And you can add new property by the static method in the config class. For your question:
// this will generate a DTO class named "resPatientView".
// You can change this name using genName attribute.
#ViewOf(value=resPatient.class, includePattern = ".*")
public class PatientViewConfigure {
// here tell the processor to automatically convert the property appointments from List<resAppointment> to List<resAppointmentWithoutPatient>.
// resAppointmentWithoutPatient is the generated class configured at the following.
// Note, although at this moment it not exists and your idea think it is an error.
// this code really can be compiled, and after compiled, all will ok.
#OverrideViewProperty("appointments")
private List<resAppointmentWithoutPatient> appointments;
}
// here generated a class named resAppointmentWithoutPatient whick has all properties of resAppointment except patient
#ViewOf(value=resAppointment.class, genName="resAppointmentWithoutPatient", includePattern = ".*", excludes={"patient"})
public class AppointmentWithoutPatientViewConfigure {
// the doctor property will be converted to its dto version which defined by the configure class DoctorWithoutAppointmentsViewConfigure.
#OverrideViewProperty("doctor")
private resDoctorWithoutAppointments doctor;
}
// here we generate a class which has all properties of resDoctor except appointments
#ViewOf(value=resDoctor.class, genName="resDoctorWithoutAppointments", includePattern = ".*", excludes={"appointments"})
public class DoctorWithoutAppointmentsViewConfigure {}
// in you rest controller. return the dto instead of the entities.
resPatient patient = ...
resPatientView dto = resPatientView.read(patient);
List<resPatient> patients = ...
List<resPatientView> dto = resPatientView.read(patients);
At the end, the class resPatientView will has the same shap with resPatient except its appointments not having patient property and its doctor property is replaced with a version without appointments property.
Here are more examples.
The version 1.10 is ready. Will fix some bug and support the configure bean to be managed by spring.

Spring Boot - creating endpoints that involve more than one database table - what is the best practice

I am doing a spring boot tutorial for fun. I understand that each entity can be defined by a model with a repository that the controller for that entity uses to create endpoints. I am wondering what is the best practice to create an endpoint in a controller that involves more than one model. I.e. we have a session model and speaker model below and i want to have a endpoint that returns all sessions with a speaker of a certain last name (many to many). Do I have to use both repositories? Is it even good practice to put this in session's controller since it also involves speaker? See the example below. Sorry if the question is stupid, I am trying to learn Spring-Boot and I am completely new to it.
//Session class
#Entity(name="sessions")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Session {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long session_id;
private String session_name;
private String session_description;
private Integer session_length;
#ManyToMany
#JoinTable(
name = "session_speakers",
joinColumns = #JoinColumn(name="session_id"),
inverseJoinColumns = #JoinColumn(name= "speaker_id"))
private List<Speaker> speakers;
}
//Speaker
#Entity(name="speakers")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Speaker {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long speaker_id;
private String first_name;
private String last_name;
private String title;
private String company;
private String speaker_bio;
#ManyToMany(mappedBy = "speakers")
#JsonIgnore
private List<Session> sessions;
#RestController
#RequestMapping("/api/v1/sessions")
public class SessionsController {
#Autowired
private SessionRepository sessionRepository;
#GetMapping
#RequestMapping("{id}")
public Session getSessionsBySpeakerName(#PathVariable String lname{
//want to implement
}
Controllers are supposed to be very light,so it would be better to have seperate controllers.
Usualy it is good to have seperate Repositories also so that later on if you want to add a new table you would not be touching the existing stable code, it sould be loosly coupled as much as possible
Here are few blog posts which I found useful.
https://www.e4developer.com/2018/08/06/spring-boot-best-practices/
https://dzone.com/articles/spring-boot-best-practices-for-microservices
https://www.javaguides.net/2019/03/spring-boot-best-practices.html

Can i use exactly same entity for two tables JPA HIBERNATE

I have a rare scenario where i have to maintain two tables say
Student_failed and Student_passed. both have exactly same schema.
#Entity
#Table(name = "student_failed")
public class StudentFailed {
#Id
#Column(name="id")
private String id;
#Column(name="student_name")
private String studentName;
#Column(name="home_town")
private String homeTown;
...
}
and
#Entity
#Table(name = "student_passed")
public class StudentPassed {
#Id
#Column(name="id")
private String id;
#Column(name="student_name")
private String studentName;
#Column(name="home_town")
private String homeTown;
...
}
as both entities are same i want to use single entity for both table. I have two different controllers that do crud operations on either of the tables.
Can i use single entity and map it to both the tables? I came across #SecondaryTables annotation but i am not sure it if will work.
PS: i know its a bad approach to keep two different tables with same fields but due to some specific requirement i am not allowed to do that).

Spring Boot one to many unidirectional

I have the entity Project and entity Cluster.
A Project can have multiple Clusters.
I don't want a third table to save this relationship. Just the Project ID saved to the Cluster.
This is my project Entity:
#Entity
#Table(name = "Project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String projectName;
#OneToMany
#JoinTable(name = "cluster")
private Set<Cluster> clusters;
}
This is my Cluster entity
#Entity
#Table(name = "Cluster")
public class Cluster {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String team;
private String concept;
}
This gives me the error: must have same number of columns as the referenced primary key .
How could I fix this? I don't see how to fix this.
Use #JoinColumn instead of #JoinTable
public class Project {
//...
#OneToMany
#JoinColumn(name="PROJECT_ID", referencedColumnName="id")
private Set<Cluster> clusters;
and add PROJECT_ID column to Cluster entity.
public class Cluster {
//...
#Column(name = "PROJECT_ID")
private Integer projectId;
Correct me if I'm wrong but, as far as I know about Software Engineering, what you want CAN'T be done: you can't store a relationship nowhere but in a third table. Lists, sets, maps, and so on MUST be stored that way.
Otherwise, and in your case, you'd have Project's properties replicated for each cluster of the relationship, and that's not desirable.

Resources