How can i apply native join query in spring data jpa? - java

Here are my entity classes.
JobPost.java
#Entity
#Table(name = "job_post")
public class JobPost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "job_post_id")
private Long jobPostId;
#Column(name = "job_title")
private String jobTitle;
#Column(name = "job_description")
private String jobDescription;
#Column(name = "vacancy")
private int vacancy;
#Column(name = "posted_date")
#JsonFormat(pattern = "yyyy-MM-dd")
private Date postedDate;
#Column(name = "total_applicants")
private int totalApplicants;
}
JobApplication.java
#Entity
#Table(name = "job_application")
public class JobApplication {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "job_application_id")
private Long jobApplicationId;
#Column(name = "job_post_id")
private Long jobPostId;
#Column(name = "applicant_id")
private Long applicantId;
}
Applicant.java
#Entity
#Table(name = "applicant")
public class Applicant {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "applicant_id")
private Long applicantId;
#Column(name = "applicant_name")
private String applicantName;
#Column(name = "applicant_mobile_no")
private String applicantMobileNo;
#Column(name = "applicant_email")
private String applicantEmail;
}
My main goal is to listing the ApplicantList on JobPostId. I am totally new in Spring data JPA. Is JPA mappings are correct?. I don't know which query I should fire in order to fetch the applicantList based on jobPostId.

I would recommend to use JpaMappings and use SpringData instead of using native query.
Steps to follow:
Many-To-Many:
Use JoinTable to directly map JobPost and Applicant instead of creating a separate class.
Link for help:
https://attacomsian.com/blog/spring-data-jpa-many-to-many-mapping
Use SpringData JPA findOne or findById method (depends on spring version). If you use EAGER fetch then it will give you all Applicants associated with the JobPost Id.
One-To-Many
Keep JobApplication class and use OneToMany annotation.
Link for help:
https://attacomsian.com/blog/spring-data-jpa-one-to-many-mapping
Query:
#Query("select a from JobPost j inner join j.jobApplicantList ja inner join ja.applicant a where j.jobPostId=:jobPostId")
List<String> findAllJobApplicants(#Param("jobPostId") Long jobPostId);

I think that you should configure the mappings in such a way.To do this, you only need two entities
JobPost.java
#Entity
#Table(name = "job_post")
public class JobPost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "job_title")
private String jobTitle;
#Column(name = "job_description")
private String jobDescription;
#Column(name = "vacancy")
private int vacancy;
#Column(name = "posted_date")
#JsonFormat(pattern = "yyyy-MM-dd")
private Date postedDate;
#Column(name = "total_applicants")
private int totalApplicants;
#ManyToMany
#JoinTable(name = "applicant_job_post",
joinColumns = {
#JoinColumn(name = "job_post_id", referencedColumnName = "id")
}, inverseJoinColumns = {
#JoinColumn(name = "applicant_id", referencedColumnName = "id")
})
private Set<Applicant> applicants;
public JobPost() {
}
public void addApplicant(Applicant applicant) {
applicants.add(applicant);
applicant.getJobPosts().add(this);
}
public void removeApplicant(Applicant applicant) {
applicants.remove(applicant);
applicant.getJobPosts().remove(this);
}
}
Applicant.java
#Entity
#Table(name = "applicant")
public class Applicant {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "applicant_name")
private String applicantName;
#Column(name = "applicant_mobile_no")
private String applicantMobileNo;
#Column(name = "applicant_email")
private String applicantEmail;
#ManyToMany(mappedBy = "applicants")
private Set<JobPost> jobPosts;
public Applicant() {
}
public void addJobPost(JobPost jobPost) {
jobPosts.add(jobPost);
jobPost.getApplicants().add(this);
}
public void removeJobPost(JobPost jobPost) {
jobPosts.remove(jobPost);
jobPost.getApplicants().remove(this);
}
}

Related

foreign key is null Springboot jpa

customer
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "customer_id")
private Long customerId;
#NonNull
#Column(name = "name")
private String name;
#NonNull
#Column(name = "address")
private String address;
#NonNull
#Column(name = "house_no")
private String houseNo;
#Column(name = "active")
private boolean active = true;
#NonNull
#Column(name = "customer_type")
private String customerType;
#NonNull
#Column(name = "pack")
private String pack;
#JsonIgnore
#OneToOne(mappedBy = "customer",cascade = CascadeType.ALL)
private Stb stb;
#JsonIgnore
#OneToOne(mappedBy = "customer",cascade = CascadeType.ALL )
private Payment payment;
#JsonIgnore
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
private List<History> history;
}
History
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "history")
public class History {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "history_id")
private Long historyId;
#Column(name = "amount_paid")
private Long AmountPaid;
#LastModifiedDate
#Column(name = "payment_date")
private String paymentDate;
#Column(name = "due")
private Long due;
#JsonIgnore
#ManyToOne(optional = false,fetch=FetchType.LAZY)
#JoinColumn(name = "customer_f_id",referencedColumnName = "customer_id")
private Customer customer;
payment
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "payment")
public class Payment {
public Long normalPrice =220L;
public Long sportsPrice = 250L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "payment_id")
private Long paymentId;
#Nonnull
#Column(name = "amount_paid")
private Long paid;
#Nullable
#LastModifiedDate
#Column(name = "payment_date")
private String paymentDate;
#Nullable
#Column(name = "due")
private Long due;
#JsonIgnore
#OneToOne(fetch=FetchType.EAGER,optional=false)
#JoinColumn(name = "customer_f_id",referencedColumnName = "customer_id")
private Customer customer;
stb
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "stbox")
public class Stb {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "stb_id")
private Long StbId;
#NonNull
#Column(name = "stbox_number")
private String StboxNumber;
#NonNull
#Column(name = "stbox_id")
private String StboxId;
#NonNull
#Column(name = "stbox_cust_number")
private String StboxCustNumber;
#NonNull
#Column(name = "stbox_type")
private String StboxType;
#JsonIgnore
#OneToOne(optional = false,fetch=FetchType.LAZY)
#JoinColumn(name = "customer_f_id",referencedColumnName = "customer_id")
private Customer customer;
im new to springboot , i just assigned foreign key in many ways i watched many tutorials and blogs and tried it out but it all failed , the foreign key is always set to null, anybody help , thanks in advance :) .
im trying to create a foreign key in stb , payment ,history but i refered it correctly but it ssets to null
Are you setting both sides of the joins?
public class Customer {
public void setStb(Stb stb) {
this.stb = stb;
stb.customer = this;
}
}
or outside maybe?
public void setCustomerStb(Customer customer, Stb stb) {
customer.setStb(stb);
stb.setCustomer(customer);
}
The same also applies to the other joins.

how to save entities in a relation to database in spring boot

I have a spring boot application with two entities in a relationship. MeetingSetting and MeetingTime meetingSetting can have unlimited meetingTimes. So far the databases are generating without problem, but When I try to save my Entity they are saved but different from each other, they are saved independently. Meaning MeetingName which is a foreign key inside MeetingTime is not saved but seen as null (I debugged and tried finding out why but could not find anything) THe other values are saved-
could someone point me out what my error is?
this is the json I am sending:
{
"meetingName":"TEst",
"meetingPw":"",
"meetingTime":[
{
"date":"2021-05-31",
"startTime":"15:30",
"endTime":"16:30"
},
{
"date":"2021-06-21",
"startTime":"15:30",
"endTime":"17:30"
},
{
"date":"2021-06-21",
"startTime":"11:01",
"endTime":"11:01"
}
]
}
MeetingSettings:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name", unique = true)
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meeting_Name", cascade = CascadeType.ALL)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
MeetingTime:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne
#JoinColumn(name = "meeting_name" ,insertable = false, updatable = false , referencedColumnName = "meeting_name")
private MeetingsSetting meeting_Name;
}
this is how I try to save the entity:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingSettingService.saveMeeting(meetingsSetting);
}
}
My service calls the save method of an jpaRepository.
In a bi-directional One to Many, you have to synchronize both sides of the association.
You can simply iterate over all MeetingTime objects and set the corresponding MeetingSetting to it.
Your MeetingSettingService's saveMeeting method could do this:
public void saveMeeting(MeetingsSetting meetingsSetting) {
// ...
// here you're synchronizing both sides of the association
meetingsSetting.getMeetingTime()
.forEach(mt -> mt.setMeetingSetting(meetingSetting));
// ...
repository.save(meetingSetting);
}
Solution to my question, I am not sure if this is a good or correct way of solving this maybe someone can advice me a better solution:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "meeting_name")
private String meeting_name;
THIS IS THE PART WHICH IS CALLED FROM THE METHOD INSIDE MEETINGSCONTROLLER
#Column(name = "end_time")
private String endTime;
#ManyToOne
#JoinColumn(name = "meeting_name" ,insertable = false, updatable = false, referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
}
MeetingsTime Entity:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingsSetting.getMeetingTime()
.forEach(mt -> mt.setMeeting_name(meetingsSetting.getMeetingName()));
// ...
meetingSettingService.saveMeeting(meetingsSetting);
}
}

Insert data to multiple tables in spring jpa

I have two tables, user and transaction. Where one user can have many transactions. So, everytime I create new user, they automatically make new transaction and the transaction type is SEND MONEY. But I don't understand how to write it in Spring JPA. Please take a look on my code and help me.
User.java
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "password")
private String password;
#Column(name = "money")
private int money;
//Getter Setter Constructor
}
Transaction.java
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_trans")
private long id_trans;
#Column(name = "id_user")
private long id_user;
#Column(name = "transaction_date")
private Timestamp transaction_date;
#Column(name = "type") //Default set as "SEND MONEY"
private String type;
#Column(name = "trans_money") //From money in User.class
private int trans_money;
//Getter Setter Constructor
}
I know I should do something in my UserDAO.java, but I still don't know how to send data from body and split(?) it into two object (user and transaction, so I can persist it in UserDAO).
First of all, you have to write the relationship between User and Transaction.
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "password")
private String password;
#Column(name = "money")
private int money;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private Set<Transaction> transactions = new HashSet<>();
//Getter Setter Constructor
}
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_trans")
private long id_trans;
#Column(name = "id_user")
private long id_user;
#Column(name = "transaction_date")
private Timestamp transaction_date;
#Column(name = "type") //Default set as "SEND MONEY"
private String type;
#Column(name = "trans_money") //From money in User.class
private int trans_money;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(referencedColumnName = "id")
private User user;
//Getter Setter Constructor
}
Then you have to create the JPA repository interface for the User
#Repository
public interface UserRepo extends CrudRepository <User, Long> {
}
Then in a service, you can do the following
#Service
public class UserService {
private UserRepo userRepo;
#Autowired
MealService(UserRepo userRepo){
this.userRepo = userRepo;
}
public void CreateNewUser(){
User user = new User();
// set its values
Transaction transaction = new Transaction();
transaction.setType("SEND MONEY");
// set other values
user.getTransactions().add(transaction);
userRepo.save(user);
}
}
Looking at the #Entity classes mentioned it seems to me that there exists an #ManyToOne association between Transaction and User which is not captured in the entity relationship modeling/mapping.
Please consider modeling that in your Transaction entity as follows,
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_trans")
private long id_trans;
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}, fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
#Column(name = "transaction_date")
private Timestamp transaction_date;
#Column(name = "type") //Default set as "SEND MONEY"
private String type;
#Column(name = "trans_money") //From money in User.class
private int trans_money;
//Getter Setter Constructor
}
Once you do that you can create a JPA repository class for Transaction and User and simply use the save method to do what you want in a transaction after constructing your instances. More on transactions in Spring Data JPA here
public interface TransactionRepository extends JpaRepository<Transaction, Long> {
}

Spring JPA Join two tables without third class

Is there a way to join two tables in Spring JPA without using association class.
I have two MySQL DB tables :
employees(id,.....,department_id)
departments(id,.....)
And I'm searching for a way to join these tables using only my employee and department classes.
Currently, I managed to join two tables but with the third association class.
My current implementation is:
Employee class:
#Entity(name = "Employee")
#Table(name = "employees")
#JsonInclude(Include.NON_NULL)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonIgnore
#Column(name = "employee_id")
private Long employeeId;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "phone_number")
private String phoneNumber;
#Column(name = "hire_date")
private Double hireDate;
#Column(name = "job_id")
private Long jobId;
#Column(name = "salary")
private Double salary;
#Column(name = "commission_pct")
private Double commissionPct;
#Column(name = "employees")
private Long employees;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private Department department;
}
Department class:
#Entity(name = "Department")
#Table(name = "departments")
#JsonInclude(Include.NON_NULL)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "department_name")
private String departmentName;
#Column(name = "department_id")
private long departmentId;
#Column(name = "manager_id")
private Double managerId;
#Column(name = "location_id")
private Double locationId;
}
Association class:
public class DeptEmpDto {
private long departmentId;
private String departmentName;
private Double managerId;
private Double locationId;
private long employeeId;
private String firstName;
private String lastName;
private String phoneNumber;
private Double hireDate;
private Long jobId;
private Double salary;
private Double commissionPct;
}
Repository:
public interface IEmployeeRepository extends JpaRepository<Employee, Long> {
#Query("SELECT new com.concretepage.entity.DeptEmpDto(d.departmentId,d.departmentName,d.managerId,d.locationId,e.employeeId,e.firstName,e.lastName,e.phoneNumber,e.hireDate,e.jobId,e.salary,e.commissionPct FROM Employee e INNER JOIN Department d ON d.id = e.jobId")
List<DeptEmpDto> fetchEmpDeptDataInnerJoin();
You can use it in Employee class
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "DeptEmp",
joinColumns = #JoinColumn(name = "emp_id",referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "dep_id",referencedColumnName = "id")
)
private Set<Departments> departments = new HashSet<>();
Look at this about JPA
Logically an employee can't work in two departements so your relationship is correct
But you can do that with a #ManyToMany annotation.

Referential integrity constraint violation error in JPA

I am trying to parse a web request and save to database. I have 3 models and first node is virtualDocument. This is the uniq table (according to request url). VirtualRequest table has all erquest bodies and HttpHeaderList table has all thhp headers according to their virtualRequest bean id.
when I tried to save the first log I got and error like this;
org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK1TW2G47F7A47580KQVMDJWGBQ: PUBLIC.T_VIRTUAL_REQUEST FOREIGN KEY(REQUEST_ID) REFERENCES PUBLIC.T_VIRTUAL_DOCUMENT(DOCUMENT_ID) (65)"; SQL statement:
insert into t_virtual_request (request_id, media_type, method_type, request_url) values (null, ?, ?, ?) [23506-192]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.192.jar:1.4.192]
here is VirtualDocument bean
#Entity
#Table(name = "t_virtual_document")
public class VirtualDocument {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "document_id")
private long documentId;
#Column(name = "real_url", unique = true)
private String realURL; //uniq
#Column(name = "virtual_url", unique = true)
private String virtualURL; //uniq
#Column(name = "simulation_mode", columnDefinition = "varchar(10) default 'STOP'")
private String simulationMode;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "request_id")
private List<VirtualRequest> requestList;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "response_id")
private List<VirtualResponse> responseList;
//getter setter without any annotation
}
here is VirtualRequest bean;
#Entity
#Table(name = "t_virtual_request")
public class VirtualRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "request_id")
private long requestId;
#Column(name = "request_url")
private String requestURL;
#Column(name = "method_type")
private String methodType;
#Column(name = "media_type")
private String mediaType;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "header_id")
private List<HttpHeaderList> requestHeaders;
//getter setter without any annotation
}
here is HeaderList bean;
#Entity
#Table(name = "t_http_headers")
public class HttpHeaderList {
#Id
#Column(name = "header_id")
private long headerId;
#Column(name = "header_key")
private String headerKey;
#Column(name = "header_value")
private String headerValue;
}
I think this is what you want instead:
#Entity
#Table(name = "t_virtual_document")
public class VirtualDocument {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "document_id")
private long documentId;
#Column(name = "real_url", unique = true)
private String realURL; //uniq
#Column(name = "virtual_url", unique = true)
private String virtualURL; //uniq
#Column(name = "simulation_mode", columnDefinition = "varchar(10) default 'STOP'")
private String simulationMode;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualDocument")
private List<VirtualRequest> requestList;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualDocument")
// Note the mappedBy parameter. This points to the property in the entity that owns the relationship (in this case the VirtualResponse).
private List<VirtualResponse> responseList;
//getter setter without any annotation
}
#Entity
#Table(name = "t_virtual_request")
public class VirtualRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "request_id")
private long requestId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "document_id")
private VirtualDocument virtualDocument;
#Column(name = "request_url")
private String requestURL;
#Column(name = "method_type")
private String methodType;
#Column(name = "media_type")
private String mediaType;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualRequest")
private List<HttpHeaderList> requestHeaders;
//getter setter without any annotation
}
#Entity
#Table(name = "t_http_headers")
public class HttpHeader { /*Note this is a more appropriate name for the entity since it holds the data of a single header.*/
#Id
#Column(name = "header_id")
private long headerId;
#Column(name = "header_key")
private String headerKey;
#Column(name = "header_value")
private String headerValue;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "request_id")
private VirtualRequest virtualRequest
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "response_id")
private VirtualResponse virtualResponse;
}
Updated the answer to add mapping the headers to the request entity.

Categories

Resources