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
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! **
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;
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
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
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;