Spring Boot Data Jpa Join Query - java

These are my model classes and when I add the json data you see below, the data is successfully placed in my database tables.
{
"RequestIdentifier": "01asdasdk12k1j21kj21k",
"Status": {
"Name": "Successful",
"Code": 0,
"Message": "null"
},
"Response": {
"Name": "PersonName",
"Surname": "PersonSurname",
"Patronymic": "PersonPatronymic",
"BirthDate": "PersonBirthdate",
"Allowance": [], //it's normal for it to be empty
"Pension": [ //Here is the part where I can't get the data. It returns empty just like Allowance.
{
"Type": {
"Label": "LabelName",
"Id": 0,
"Description": "description"
},
"StartDate": "05.12.2021",
"EndDate": "null",
"Group": null,
"Amount": 5154540
}
]
}
}
package com.example.sifirdanapi.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
import java.util.Set;
#Entity
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#ToString
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "allowance", "pension"})
public class PensionInfoResult {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_Sequence")
#SequenceGenerator(name = "id_Sequence", sequenceName = "ID_SEQ")
private Long id;
private String RequestIdentifier;
private String name;
private String surname;
private String patronymic;
private String birthDate;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#LazyCollection(LazyCollectionOption.FALSE)
#Fetch(value = FetchMode.SUBSELECT)
private Set<PensionInfoAllowance> allowance;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#LazyCollection(LazyCollectionOption.FALSE)
#Fetch(value = FetchMode.SUBSELECT)
private Set<PensionInfoPension> pension;
//--------------------------------------------
private String pin;
private String branchCode;
private String username;
#Column(name = "CREATED_DATE")
#Temporal(TemporalType.TIMESTAMP)
#CreatedDate
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private Date createdDate;
#Lob
#Column
private String request;
private String statusCode;
private String statusMessage;
private String statusName;
#Lob
#Column
private String response;
#PrePersist
public void persist() {
setCreatedDate(new Date());
}
}
package com.example.sifirdanapi.model;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class PensionInfoPension {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_Sequence")
#SequenceGenerator(name = "id_Sequence", sequenceName = "ID_SEQ")
private Long id;
private String startDate;
private String endDate;
private BigDecimal amount;
private Integer typeId;
private String typeDesc;
private String typeLabel;
private Integer groupId;
private String groupdesc;
#ManyToOne(fetch = FetchType.EAGER)
private PensionInfoResult pensionInfoResult;
#Column(name = "CREATED_DATE")
#Temporal(TemporalType.TIMESTAMP)
#CreatedDate
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private Date createdDate;
#PrePersist
public void persist() {
setCreatedDate(new Date());
}
}
package com.example.sifirdanapi.model;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class PensionInfoAllowance {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_Sequence")
#SequenceGenerator(name = "id_Sequence", sequenceName = "ID_SEQ")
private Long id;
private String beginDate;
private String endDate;
private BigDecimal amount;
private Integer groupId;
private String groupDesc;
private Integer typeId;
private String typeDesc;
#ManyToOne(fetch = FetchType.EAGER)
private PensionInfoResult pensionInfoResult;
#Column(name = "CREATED_DATE")
#Temporal(TemporalType.TIMESTAMP)
#CreatedDate
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private Date createdDate;
public Date getCreatedDate() {
return createdDate;
}
}
So I don't have any problems in the relationship part. I just couldn't figure out how to write the query I have shown below in spring boot data jpa. When I run the following query in sql, it successfully returns the data I want, but I cannot export it to java.
SELECT
*
FROM
pension_info_result AS pir
JOIN
pension_info_pension AS pip ON pir.id = pip.pension_info_result_id
JOIN
pension_info_allowance as pia ON pir.id = pia.pension_info_result_id
where pir.id=?
#Query(value =
"""
select pif from PensionInfoResult pif
join PensionInfoPension pip on if.id=pip.pensionInfoResult.id
join PensionInfoAllowance pia on pif.id=pia.pensionInfoResult.id
where pif.id=?1
"""
, nativeQuery = true)
PensionInfoResult findById(Long id);
When I run the program it gives me the following error.
java.sql.SQLSyntaxErrorException: Table 'api.pensioninforesult' doesn't exist
How can I write the query I showed above more accurately?

Related

Spring ModelMapping error appeared when I try to convert Post to PostDTO,if I replace #Data annotation with #Getter, #Setter, it works perfectly

package com.springboot.blog.entity;
import lombok.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "posts")
public class Post {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
#Column(name = "title", nullable = false)
private String title;
#Column(name = "description", nullable = false)
private String description;
#Column(name = "content", nullable = false)
private String content;
#OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Comment> comments = new HashSet<>();
}
Here is the Post class
package com.springboot.blog.payload;
import lombok.Data;
import java.util.Set;
#Data
public class PostDTO {
private Long id;
private String title;
private String description;
private String content;
private Set<CommentDTO> comments;
}
Here is PostDTO class.
#Override
public PostDTO getPost(Long id) {
Post temp_post = postRepository.findById(id).
orElseThrow(() -> new ResourceNotFoundException("Post", "Id", id));
return mapToDTO(temp_post);
}
private PostDTO mapToDTO(Post post) {
return modelMapper.map(post, PostDTO.class);
}
I used mapToDTO method to convert post to postDTO.
But When I test it, the error message appeared.
{"timestamp":"2022-04-30T14:03:03.369+00:00","status":500,"error":"Internal Server Error","trace":"org.modelmapper.MappingException: ModelMapper mapping errors:\n\n1) Error mapping com.springboot.blog.entity.Post to com.springboot.blog.payload.PostDTO\n\n1 error\n\tat org.modelmapper.internal.Errors.throwMappingExceptionIfErrorsExist(Errors.java:380)\n\tat org.modelmapper.internal.
========================================================================================
** But when I replace the #Data annotation in class Post with #Getter, #Setter. It works perfectly! **

Mapping between two classes with JpaRepository SpringBoot

Well I have a class Service and a class Employee
Service.java
import lombok.Data;
import javax.persistence.*;
#Data
#Table(name = "services")
#Entity
public class ServiceResource {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String date;
private String longitude;
private String latitude;
#ManyToOne
#JoinColumn(name="employee_id")
private EmployeeResource employee;
}
Employee.java
import lombok.Data;
import javax.persistence.*;
#Data
#Table(name = "employees")
#Entity
public class EmployeeResource {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String longitude;
private String latitude;
}
Now I'd like to build my application that the mapping between service and employee is done with JPA. Is that even possible and how?
Add this to your EmployeeResource Entity:
#OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
private List<ServiceResource> serviceList;
and in ServiceResource, modify the join column like this:
#ManyToOne
#JoinColumn(name="employee_id", referencedColumnName = "id")
private EmployeeResource employee;

Whole table not showing in JSON when doing Hibernate mapping

The table is created successfully and filled with information in H2 database as seen here:
When using Spring boot to display this table information with JSON format i only see this:
Here you can see the code snippet from the object
package com.share.sharelt.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.Data;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Data
#Table(name = "item_rental")
public class ItemRental {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "created")
private Date created;
#Column(name = "cost")
BigDecimal cost;
#Column(name = "rent_begin")
private Date rentBegin;
#Column(name = "rent_end")
private Date rentEnd;
#Column(name = "is_confirmed")
private boolean isConfirmed;
#JsonBackReference
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "renter_id", nullable = true)
private User user;
public ItemRental(){};
}
The problem is that i want to see the whole table information, more specifically the "renter_id" column
One of the solutions is to create a DTO class which is gonna be a JSON wrapper to your ItemRental entity
Something like ItemRentalDTO and UserDTO with all fields of ItemRental and User entity class
Link: https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

How to map the results of a stored procedure to an entity in spring-boot/hibernate

I have an Entity class as seen below
NB: The checkNumber is unique.
package tz.go.ega.biometic.entity;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import lombok.ToString;
import org.hibernate.annotations.NaturalId;
import org.hibernate.validator.constraints.SafeHtml;
import org.springframework.data.annotation.Transient;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Table(name = "employee", uniqueConstraints = {
#UniqueConstraint(columnNames = {"check_number"})
})
#Data
#AllArgsConstructor
#ToString
#NoArgsConstructor
public class Employee implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#Basic(optional = true)
//#NotEmpty(message = "Please enter first name")
#Column(name = "first_name")
private String firstName;
#Basic(optional = true)
//#NotEmpty(message = "Please enter middle name")
#Column(name = "middle_name")
private String middleName;
#Basic(optional = true)
//#NotEmpty(message = "Please enter last name")
#Column(name = "last_name")
private String lastName;
private String status;
#Basic(optional = true)
// #Pattern(regexp ="^[a-zA-Z0-9_]*$",message = "{field.validation.voteCode}")
// #SafeHtml(message = "{field.validation.voteCode}")
#Column(name = "vote_code", length = 50)
private String voteCode;
#NaturalId
#Basic(optional = true)
//#NotNull(message = "Please enter check number")
#Column(name = "check_number")
private long checkNumber;
private Boolean isActive = true;
#Basic(optional = false)
#Column(name = "created_at", updatable = false)
#DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
private LocalDateTime createdAt = LocalDateTime.now();
#Column(name = "updated_at")
#DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
private LocalDateTime updatedAt = LocalDateTime.now();
#Column(name = "email")
private String email;
}
I then have a stored procedure that calculates each employee's working hours then returns the results as seen below.
+--------------+-------+
| checkNumber | Time |
+--------------+-------+
| 1122334455 | 29893 |
| 1234567890 | 15427 |
| 2233445566 | 19745 |
| 6655443322 | 12578 |
+--------------+-------+
What I am trying to achieve is, to map the results ( as seen above ) of the stored procedure to an entity (let's call it EmployeeWorkHours ) and then create a relationship between this Entity and the Employee entity using the checkNumber.
I want the EmployeeWorkHours object to be able to reference it's employee directly like in normal hibernate relationships.
How can I go about this, any help will be much appreciated. Thank you.
On your EmployeeWorkHours entity you need a OneToOne relationship with Employee entity
#OneToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name = "checkNumber", unique = true, nullable = false)
private Employee employee;
In your repository you can write a sql query like this :
#Query(value = "{CALL yourStoredProcedure (:var1, :var2, ..., :varn)}", nativeQuery = true)
int getWorkHours(#Param("var1") String var1, #Param("var2") String var2,...,
#Param("varn") String varn);
And then in your service layer you will just call this method do what else you want and persist it.
Hope it helps

JPA OneToOne find all stuck in loop

I've a Java REST API with JPA. Whenever I create an entity, I also want to create another entity with a forgein key. Or maybe someone can advise me otherwise, I would really appreciate it and learn from it =)
When i successfully create a company it will make a file entity in the database as well, so that works fine. but,
Whenever I execute a findAll method in the JPA repository it will give me a loop of the one company that i've created.
like this:
If you need any more information, please let me know!
Company.class
package nl.hulpvriend.dehulpvriend.company;
import javax.validation.constraints.NotNull;
import lombok.*;
import nl.hulpvriend.dehulpvriend.file.File;
import javax.persistence.*;
import javax.validation.constraints.Size;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
private String email;
#Column(unique = true)
#NotNull(message = "The company name cannot be empty")
#Size(max = 30, message = "Company name cannot be longer than 30 characters")
private String name;
#NotNull(message = "Company must contain a service type")
#Enumerated(EnumType.STRING)
private ServiceType serviceType;
private double stars;
private Integer pricePerHour;
private String description;
private String kvk;
#OneToOne(mappedBy="company", cascade = CascadeType.ALL)
private File file;
}
File.class
package nl.hulpvriend.dehulpvriend.file;
import lombok.*;
import nl.hulpvriend.dehulpvriend.company.Company;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
#AllArgsConstructor
#Getter
#Setter
#NoArgsConstructor
#Entity
#Data
public class File {
#Id
private Integer id;
private String fileId;
#OneToOne(fetch = FetchType.EAGER)
#MapsId
private Company company;
#NotNull(message = "Must contain a data")
#Lob
private byte[] data;
private String downloadUrl;
private String fileName;
private String fileType;
public File(String fileName, String fileType, byte[] data) {
this.fileName = fileName;
this.fileType = fileType;
this.data = data;
}
}
Add JsonIgnore to one of the references to break the loop:
For example in the File class:
#JsonIgnore
#OneToOne(fetch = FetchType.EAGER)
#MapsId
private Company company;

Categories