OneToOne relation inside Json - spring

I created an SecretData object whitch I am sending to frontend:
package pl.portal.randkowy.model;
import com.fasterxml.jackson.annotation.JsonBackReference;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
#Entity(name = "SecretData")
#Table(
name = "secret_data",
uniqueConstraints = {
#UniqueConstraint(
name = "secret_data_id_unique",
columnNames = "id")
}
)
public class SecretData {
#Id
#SequenceGenerator(
name = "secret_data_sequence",
sequenceName = "secret_data_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = SEQUENCE,
generator = "secret_data_sequence"
)
#Column(
name = "id",
updatable = false,
unique = true
)
private Long id;
#Column(
name = "login",
nullable = true,
columnDefinition = "TEXT"
)
private String login;
#Column(
name = "password",
nullable = true,
columnDefinition = "TEXT"
)
private String password;
#Column(
name = "role",
nullable = true,
columnDefinition = "TEXT"
)
private String role;
#Column(
name = "private_email",
nullable = true,
columnDefinition = "TEXT"
)
private String privateEmail;
//1-kierunkowa relacja
#OneToOne(
cascade = CascadeType.ALL,
fetch = FetchType.EAGER, //domyślne
orphanRemoval = true
)
#JoinColumn(
name = "person_id", //nazwa kolumny w tabeli bazy danych
referencedColumnName = "id", //nazwa pola z klasy Person po którym idzie relacja
nullable = true,
foreignKey = #ForeignKey(
name = "person_secret_data_fk"
)
)
#JsonBackReference
private Person person;
public SecretData() {
}
public SecretData(String login, String password, String role, String privateEmail) {
this.login = login;
this.password = password;
this.role = role;
this.privateEmail = privateEmail;
}
public SecretData(String login, String password, String role, String privateEmail, Person person) {
this.login = login;
this.password = password;
this.role = role;
this.privateEmail = privateEmail;
this.person = person;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getPrivateEmail() {
return privateEmail;
}
public void setPrivateEmail(String privateEmail) {
this.privateEmail = privateEmail;
}
#Override
public String toString() {
return "SecretData{" +
"id=" + id +
", login='" + login + '\'' +
", password='" + password + '\'' +
", role='" + role + '\'' +
", privateEmail='" + privateEmail + '\'' +
'}';
}
}
It has OneToOne relation to Person
package pl.portal.randkowy.model;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static javax.persistence.GenerationType.SEQUENCE;
#Entity(name = "Person")
#Table(
name = "persons",
uniqueConstraints = {
#UniqueConstraint(
name = "person_email_unique",
columnNames = "email")
}
)
public class Person {
#Id
#SequenceGenerator(
name = "person_sequence",
sequenceName = "person_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = SEQUENCE,
generator = "person_sequence"
)
#Column(
name = "id",
updatable = false
)
private Long id;
#Column(
name = "name",
nullable = true,
columnDefinition = "TEXT"
)
private String name;
#Column(
name = "last_name",
nullable = true,
columnDefinition = "TEXT"
)
private String lastName;
#Column(
name = "date_of_birth",
nullable = true,
columnDefinition = "DATE"
)
private Date dateOfBirth;
#Column(
name = "sex",
nullable = true,
columnDefinition = "TEXT"
)
private String sex;
#Column(
name = "sexual_orientation",
nullable = true,
columnDefinition = "TEXT"
)
private String sexualOrientation;
#Column(
name = "marital_status",
nullable = true,
columnDefinition = "TEXT"
)
private String maritalStatus;
#Column(
name = "province",
nullable = true,
columnDefinition = "TEXT"
)
private String province;
#Column(
name = "city",
nullable = true,
columnDefinition = "TEXT"
)
private String city;
#Column(
name = "self_description",
nullable = true,
columnDefinition = "TEXT"
)
private String selfDescription;
#Column(
name = "life_motto",
nullable = true,
columnDefinition = "TEXT"
)
private String lifeMotto;
#Column(
name = "thought_of_the_day",
nullable = true,
columnDefinition = "TEXT"
)
private String thoughtOfTheDay;
#Column(
name = "photo",
nullable = true,
columnDefinition = "TEXT"
)
private String photo;
#Column(
name = "profession",
nullable = true,
columnDefinition = "TEXT"
)
private String profession;
#Column(
name = "education",
nullable = true,
columnDefinition = "TEXT"
)
private String education;
#Column(
name = "email",
nullable = true,
columnDefinition = "TEXT"
)
private String email;
//trzeba dodać, żeby z relacji 1-kierunkowej zrobić relacje 2-kierunkową
#OneToOne(
mappedBy = "person",
orphanRemoval = false,
cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.MERGE}
) //pole po którym idzie relacja z klasy SecretData
#JsonManagedReference
private SecretData secretData;
//trzeba dodać, żeby z relacji 1-kierunkowej zrobić relacje 2-kierunkową
#OneToOne(
mappedBy = "person",
orphanRemoval = false,
cascade = CascadeType.ALL
) //pole po którym idzie relacja z klasy Preference
private Preference preference;
//jeśli ma być 2-kierunkowa to też tutaj trzeba dodać poniższy wpis i metody poniżej
#OneToMany(
mappedBy = "person",
orphanRemoval = true,
cascade = CascadeType.ALL,
fetch = FetchType.LAZY //domyślna wartość
)
private List<Proposition> propositions = new ArrayList<>();
#OneToMany(
mappedBy = "sender",
orphanRemoval = true,
cascade = CascadeType.ALL,
fetch = FetchType.LAZY //domyślna wartość
)
private List<Email> emails = new ArrayList<>();
#ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.REMOVE}
)
#JoinTable(
name = "person_interest",
joinColumns = #JoinColumn(
name = "person_id",
foreignKey = #ForeignKey(name = "person_id_fk")
),
inverseJoinColumns = #JoinColumn(
name = "interest_id",
foreignKey = #ForeignKey(name = "interest_id_fk")
)
)
private List<Interest> interests = new ArrayList<>();
public Person() {
}
public Person(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public Person(String name, String lastName, Date dateOfBirth, String sex, String sexualOrientation, String maritalStatus, String province, String city, String selfDescription, String lifeMotto, String thoughtOfTheDay, String photo, String profession, String education, String email) {
this.name = name;
this.lastName = lastName;
this.dateOfBirth = dateOfBirth;
this.sex = sex;
this.sexualOrientation = sexualOrientation;
this.maritalStatus = maritalStatus;
this.province = province;
this.city = city;
this.selfDescription = selfDescription;
this.lifeMotto = lifeMotto;
this.thoughtOfTheDay = thoughtOfTheDay;
this.photo = photo;
this.profession = profession;
this.education = education;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSexualOrientation() {
return sexualOrientation;
}
public void setSexualOrientation(String sexualOrientation) {
this.sexualOrientation = sexualOrientation;
}
public String getMaritalStatus() {
return maritalStatus;
}
public void setMaritalStatus(String maritalStatus) {
this.maritalStatus = maritalStatus;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getSelfDescription() {
return selfDescription;
}
public void setSelfDescription(String selfDescription) {
this.selfDescription = selfDescription;
}
public String getLifeMotto() {
return lifeMotto;
}
public void setLifeMotto(String lifeMotto) {
this.lifeMotto = lifeMotto;
}
public String getThoughtOfTheDay() {
return thoughtOfTheDay;
}
public void setThoughtOfTheDay(String thoughtOfTheDay) {
this.thoughtOfTheDay = thoughtOfTheDay;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public String getEducation() {
return education;
}
public void setEducation(String education) {
this.education = education;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<Interest> getInterests() {
return interests;
}
public void addInterest(Interest interest) {
interests.add(interest);
interest.getPersons().add(this);
}
public void removeInterest(Interest interest) {
interests.remove(interest);
interest.getPersons().remove(this);
}
public List<Proposition> getPropositions() {
return propositions;
}
public void addProposition(Proposition proposition) {
if (!this.propositions.contains(proposition)) {
this.propositions.add(proposition);
proposition.setPerson(this);
}
}
public void addEmail(Email email) {
if (!this.emails.contains(email)) {
this.emails.add(email);
email.setSender(this);
}
}
public void removeProposition(Proposition proposition) {
if (this.propositions.contains(proposition)) {
this.propositions.remove(proposition);
proposition.setPerson(null);
}
}
public void removeEmail(Email email) {
if (this.emails.contains(email)) {
this.emails.remove(email);
email.setSender(null);
}
}
public void setSecretData(SecretData secretData) {
this.secretData = secretData;
}
public SecretData getSecretData() {
return secretData;
}
public Preference getPreference() {
return preference;
}
public void setPreference(Preference preference) {
preference.setPerson(this);
this.preference = preference;
}
public void setPropositions(List<Proposition> propositions) {
this.propositions = propositions;
}
public void setInterests(List<Interest> interests) {
this.interests = interests;
}
public List<Email> getEmails() {
return emails;
}
public void setEmails(List<Email> emails) {
this.emails = emails;
}
#Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", lastName='" + lastName + '\'' +
", dateOfBirth=" + dateOfBirth +
", sex='" + sex + '\'' +
", sexualOrientation='" + sexualOrientation + '\'' +
", maritalStatus='" + maritalStatus + '\'' +
", province='" + province + '\'' +
", city='" + city + '\'' +
", selfDescription='" + selfDescription + '\'' +
", lifeMotto='" + lifeMotto + '\'' +
", thoughtOfTheDay='" + thoughtOfTheDay + '\'' +
", photo='" + photo + '\'' +
", profession='" + profession + '\'' +
", education='" + education + '\'' +
", email='" + email + '\'' +
", secretData=" + secretData +
", preference=" + preference +
", propositions=" + propositions +
", emails=" + emails +
", interests=" + interests +
'}';
}
}
When I am using Postman/Angular to get the data via REST
Controller
#GetMapping("/all")
public ResponseEntity <List<SecretData>> getAllSecretData(){
List<SecretData> secretDataList = secretDataService.findAllSecretData();
return new ResponseEntity<>(secretDataList, HttpStatus.OK);
}
Service
public List<SecretData> findAllSecretData(){
return secretDataRepository.findAll();
}
I am not getting the Person object inside SecredData in JSON.
How can I include this data to sended response? (an object inside second object).
I am trying to use now DTO, but without DTO it also did not work.

You should create a new class that should represent the output format you need in your response.
The SecretDataOutput class that represents the output format
public class SecretDataOutput {
private long id;
private String login, password, role, privateEmail;
private Person person;
public SecretDataOutput(long id, String login, String password, String role, String privateEmail, Person person) {
this.id = id;
this.login = login;
this.password = password;
this.role = role;
this.privateEmail = privateEmail;
this.person = person;
}
//getters and setters
Use this method to fetch all secrets in your controller:
#GetMapping("/allSecrets")
public ResponseEntity<List<SecretDataOutput>> getAllSecretData() {
Iterable<SecretData> allSecretData = service.findAllSecretData();
List<SecretDataOutput> secretDataOutputList = new ArrayList<>();
allSecretData.forEach(secretData -> {
long id = secretData.getId();
String login = secretData.getLogin();
String password = secretData.getPassword();
String privateEmail = secretData.getPrivateEmail();
String role = secretData.getRole();
Person person = secretData.getPerson();
SecretDataOutput secretDataOutput = new SecretDataOutput(id, login, password, role, privateEmail, person);
secretDataOutputList.add(secretDataOutput);
});
return new ResponseEntity<>(secretDataOutputList, HttpStatus.OK);
}
Also, I am expecting when saving a Person to a SecretData , you are doing a bi-directional mapping:
#GetMapping("/addSecret")
public String storeSecretData() {
Person p = new Person("pname", "pLastName", new Date(), "male", "pOrientation", "unmarried", "pProvince", "pCity", "pSelfDesc",
"pLifeMotto", "pThought", "pPhoto", "pProfession", "pEducation", "pEmail");
SecretData data = new SecretData("secretLogin", "secretPassword", "secretRole", "secretPrivateEmail");//use this constructor and not the one with the extra Person parameter
data.addPerson(p); //new method to be added in SecretData class
try {
service.saveSecret(data);
return "Saved";
} catch (Exception e) {
return "Failed";
}
}
Add this method to your SecretData class :
public void addPerson(Person person) {
this.person = person;
person.setSecretData(this);
}
This will be the output in Postman

Related

Issue with Join Fetch Hibernate query

I am new using hibernate join fetch queries and would like some help on the below matter.
I have one Entity that has quite a few OneToMany associations. And in the rest call
I need to load all of those associations to prepare the result.
I was using Jpa findAll(Pageable) method however on production seeing huge load on read queries. I understand that I ran into N+1 problem which I am trying to solve however getting bellow error:
{
"title" : "Internal Server Error",
"status" : 500,
"detail" : "firstResult/maxResults specified with collection fetch. In memory pagination was about to be applied. Failing because 'Fail on pagination over collection fetch' is enabled.; nested exception is org.hibernate.HibernateException: firstResult/maxResults specified with collection fetch. In memory pagination was about to be applied. Failing because 'Fail on pagination over collection fetch' is enabled.",
"cause" : {
"title" : "Internal Server Error",
"status" : 500,
"detail" : "firstResult/maxResults specified with collection fetch. In memory pagination was about to be applied. Failing because 'Fail on pagination over collection fetch' is enabled."
}
}
====================
using Running with Spring Boot v2.5.4, Spring v5.3.9 and mysql 5.7
Here is my code snippet:
Entity:
package com.pitstop.catalogue.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.pitstop.catalogue.util.EligibleOffer;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.time.Instant;
import java.util.*;
/**
* A Product.
*/
#Entity
#Table(name = "product")
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
public static final String PRODUCT_NAME = "name";
public static final String PRODUCT_CATEGORY = "category_id";
public static final String PRODUCT_UNIT_PRICE = "unit_price";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(max = 250)
#Column(name = PRODUCT_NAME, length = 50, nullable = false)
private String name;
#Size(max = 1000)
#Column(name = "description", length = 200)
private String description;
private Long brandId;
#Size(max = 500)
#Column(name = "product_icon_url", length = 500)
private String productIconUrl;
#Column(name = PRODUCT_UNIT_PRICE)
private Double unitPrice;
#Column(name = "gst_rate")
private Double gstRate;
#Size(max = 45)
#Column(name = "part_no", length = 45)
private String partNo;
#Size(max = 45)
#Column(name = "serial_no", length = 45)
private String serialNo;
#Size(max = 45)
#Column(name = "unit_type", length = 45)
private String unitType;
#Column(name = "line_item_id")
private Long lineItemId;
private Long categoryId;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(FetchMode.JOIN)
#JsonIgnoreProperties(value = {"product"}, allowSetters = true)
#BatchSize(size = 20)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private Set<Offer> offers = new HashSet<>();
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(FetchMode.JOIN)
#JsonIgnoreProperties(value = {"product"}, allowSetters = true)
#BatchSize(size = 20)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private Set<ProductAttributes> productAttributes = new HashSet<>();
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(FetchMode.JOIN)
#JsonIgnoreProperties(value = {"product", "productModel"}, allowSetters = true)
#BatchSize(size = 20)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private Set<ProductModelMapping> productModelMappings = new HashSet<>();
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(FetchMode.JOIN)
#JsonIgnoreProperties(value = {"product"}, allowSetters = true)
#BatchSize(size = 20)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private Set<ProductSeller> productSellers = new HashSet<>();
#Size(max = 45)
#Column(name = "tag", length = 50)
private String tag;
#Column(name = "created")
private Instant created;
#Column(name = "created_by", length = 100)
private String createdBy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getProductIconUrl() {
return productIconUrl;
}
public void setProductIconUrl(String productIconUrl) {
this.productIconUrl = productIconUrl;
}
public Double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(Double unitPrice) {
this.unitPrice = unitPrice;
}
public Double getGstRate() {
return gstRate;
}
public void setGstRate(Double gstRate) {
this.gstRate = gstRate;
}
public String getPartNo() {
return partNo;
}
public void setPartNo(String partNo) {
this.partNo = partNo;
}
public String getSerialNo() {
return serialNo;
}
public void setSerialNo(String serialNo) {
this.serialNo = serialNo;
}
public String getUnitType() {
return unitType;
}
public void setUnitType(String unitType) {
this.unitType = unitType;
}
public Set<Offer> getOffers() {
return offers;
}
public void setOffers(Set<Offer> offers) {
this.offers = offers;
}
public Set<ProductAttributes> getProductAttributes() {
return productAttributes;
}
public void setProductAttributes(Set<ProductAttributes> productAttributes) {
this.productAttributes = productAttributes;
}
public Set<ProductModelMapping> getProductModelMappings() {
return productModelMappings;
}
public void setProductModelMappings(Set<ProductModelMapping> productModelMappings) {
this.productModelMappings = productModelMappings;
}
public Set<ProductSeller> getProductSellers() {
return productSellers;
}
public void setProductSellers(Set<ProductSeller> productSellers) {
this.productSellers = productSellers;
}
public Long getLineItemId() {
return lineItemId;
}
public void setLineItemId(Long lineItemId) {
this.lineItemId = lineItemId;
}
#Transient
public double getSellingPrice() {
// As discussed with Rohit, iterate over all the valid offers (by date)
// and then apply which has the highest discount value. This is for Pitstop offers only.
// Sellers offers will be created by sellers.
if (this.offers.size() > 0) {
Double sellingPriceFromOffers = EligibleOffer.apply(this.offers, this.unitPrice);
return sellingPriceFromOffers;
}
return this.unitPrice;
}
#Transient
public double getProductUnitPrice() {
return this.unitPrice;
}
#Transient
public double getProductGstRate() {
if (callSellers() != null && callSellers().size() > 0) {
ProductSeller productSeller = callSellers().get(0);
return productSeller.getGstRate();
}
return gstRate;
}
#Transient
public List<ProductSeller> callSellers() {
//sorting products by seller price in ascending order
List<ProductSeller> sellers = new ArrayList<>();
sellers.addAll(productSellers);
Collections.sort(sellers, (Comparator.comparing(ProductSeller::getUnitPrice)));
return sellers;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Instant getCreated() {
return created;
}
public void setCreated(Instant created) {
this.created = created;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Long getBrandId() {
return brandId;
}
public void setBrandId(Long brandId) {
this.brandId = brandId;
}
public Long getCategoryId() {
return categoryId;
}
public void setCategoryId(Long categoryId) {
this.categoryId = categoryId;
}
#Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", description='" + description + '\'' +
", brand=" + brandId +
", productIconUrl='" + productIconUrl + '\'' +
", unitPrice=" + unitPrice +
", gstRate=" + gstRate +
", partNo='" + partNo + '\'' +
", serialNo='" + serialNo + '\'' +
", unitType='" + unitType + '\'' +
", lineItemId=" + lineItemId +
", category=" + categoryId +
", offers=" + offers +
", productAttributes=" + productAttributes +
", productModelMappings=" + productModelMappings +
", productSellers=" + productSellers +
", tag='" + tag + '\'' +
", created=" + created +
", createdBy='" + createdBy + '\'' +
'}';
}
}
Repository:
#Repository
public interface ProductRepository extends JpaRepository<Product, Long>, JpaSpecificationExecutor<Product> {
List<Product> findAllByCategoryId(Long categoryId);
List<Product> findAllByBrandId(Long brandId);
#Query(value = "select p " +
"from Product p " +
"left join fetch p.productAttributes productAttributes",
countQuery = "select count(p) from Product p")
Page<Product> findAll(Pageable pageable);
}

How to get rid of "Could not write JSON: failed to lazily initialize a collection of role" if i have #Transactional and JOIN FETCH?

I have Rest #GetMapping method :
#GetMapping(value = "/getAdmin",produces = "application/json")
public List<Users> listOfUsers(){
return userService.findAllUsers();
}
findAllUsers function looks like :
#Override
#Transactional
public List<Users> findAllUsers() {
String hqlRequest = "from Users U JOIN FETCH U.roles";
Query query = sessionFactory.getCurrentSession().createQuery(hqlRequest);
}
That is, JOIN FETCH works fine if i just call:
List<Users> users = userService.findAllUsers();
System.out.println(users);
but when a request is sent to the listOfUsers method, I get an error:
Could not write JSON: failed to lazily initialize a collection of role
I have read solutions to this problem and there it is advised to add the #Transaction annotation or use joint fetch in the request, but I have both, but I still get an error.Can someone explain how to get rid of this error and?
Users
package com.example.securityWithHibernate.Model;
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import java.util.Set;
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
#Length(min = 5, message = "*Your user name must have at least 5 characters")
#NotEmpty(message = "*Please provide a user name")
private String name;
#Column(name = "first_name")
#NotEmpty(message = "*Please provide your name")
private String firstName;
#Column(name = "last_name")
#NotEmpty(message = "*Please provide your last name")
private String lastName;
#Column(name = "email")
#Email(message = "*Please provide a valid Email")
#NotEmpty(message = "*Please provide an email")
private String email;
#Column(name = "user_password")
#Length(min = 5, message = "*Your password must have at least 5 characters")
#NotEmpty(message = "*Please provide your password")
private String userPassword;
public Set<Roles> getRoles() {
return roles;
}
public void setRoles(Set<Roles> roles) {
this.roles = roles;
}
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "user_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Roles> roles;
public Users(Long id, String name, String firstName, String lastName, String email, String userPassword) {
this.id = id;
this.name = name;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.userPassword = userPassword;
}
/*public Users( String name, String firstName, String lastName, String email, String userPassword) {
this.name = name;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.userPassword = userPassword;
}*/
public Users() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
#Override
public String toString() {
return "Users{" +
"id=" + id +
", name='" + name + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", userPassword='" + userPassword + '\'' +
", roles=" + roles +
'}';
}
}
Roles
package com.example.securityWithHibernate.Model;
import javax.persistence.*;
import java.util.Set;
#Entity
#Table(name = "roles")
public class Roles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
public Roles(Long id, String role) {
this.id = id;
this.role = role;
}
public Roles() {
}
#Column(name = "role_name")
private String role;
#ManyToMany(mappedBy = "roles")
private Set<Users> users;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Set<Users> getUsers() {
return users;
}
public void setUsers(Set<Users> users) {
this.users = users;
}
#Override
public String toString() {
return "Roles{" +
"id=" + id +
", role='" + role + '\'' +
'}';
}
}

How to retrieve data from a one to one mapped entity after a filter is applied on to the mapped entity's attribute spring

How to retrieve data from a one to one mapped entity after a filter is applied on to the mapped entity's attribute.
This is my Hotel Entity Class..
package com.springmvcweb.model;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(name = "HOTEL", schema = "HOTEL")
public class HotelEntity implements Serializable{
private long hotelId;
private String hotelName;
private String hotelDescription;
private String hotelWebsite;
private Long hotelPhoneNo;
private String hotelEmail;
private Long hotelStarRating;
private AddressEntity addressEntity;
private CategoryEntity categoryEntity;
private List<AmenityEntity> amenitiesList;
#ManyToMany(cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.DETACH,CascadeType.REFRESH})
#JoinTable(name = "HOTEL_AMENITY", joinColumns = {#JoinColumn(name = "HOTEL_ID", referencedColumnName = "HOTEL_ID")},
inverseJoinColumns = {#JoinColumn(name = "AMENITY_ID", referencedColumnName = "AMENITY_ID")})
public List<AmenityEntity> getAmenitiesList() {
return amenitiesList;
}
public void setAmenitiesList(List<AmenityEntity> amenitiesList) {
this.amenitiesList = amenitiesList;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "HOTEL_ADDRESS_ID")
public AddressEntity getAddressEntity() {
return addressEntity;
}
public void setAddressEntity(AddressEntity addressEntity) {
this.addressEntity = addressEntity;
}
#ManyToOne(cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.DETACH,CascadeType.REFRESH})
#JoinColumn(name = "HOTEL_CATEGORY_ID")
public CategoryEntity getCategoryEntity() {
return categoryEntity;
}
public void setCategoryEntity(CategoryEntity categoryEntity) {
this.categoryEntity = categoryEntity;
}
#Id
#Column(name = "HOTEL_ID")
public long getHotelId() {
return hotelId;
}
public void setHotelId(long hotelId) {
this.hotelId = hotelId;
}
#Basic
#Column(name = "HOTEL_NAME")
public String getHotelName() {
return hotelName;
}
public void setHotelName(String hotelName) {
this.hotelName = hotelName;
}
#Basic
#Column(name = "HOTEL_DESCRIPTION")
public String getHotelDescription() {
return hotelDescription;
}
public void setHotelDescription(String hotelDescription) {
this.hotelDescription = hotelDescription;
}
#Basic
#Column(name = "HOTEL_WEBSITE")
public String getHotelWebsite() {
return hotelWebsite;
}
public void setHotelWebsite(String hotelWebsite) {
this.hotelWebsite = hotelWebsite;
}
#Basic
#Column(name = "HOTEL_PHONE_NO")
public Long getHotelPhoneNo() {
return hotelPhoneNo;
}
public void setHotelPhoneNo(Long hotelPhoneNo) {
this.hotelPhoneNo = hotelPhoneNo;
}
#Basic
#Column(name = "HOTEL_EMAIL")
public String getHotelEmail() {
return hotelEmail;
}
public void setHotelEmail(String hotelEmail) {
this.hotelEmail = hotelEmail;
}
#Basic
#Column(name = "HOTEL_STAR_RATING")
public Long getHotelStarRating() {
return hotelStarRating;
}
public void setHotelStarRating(Long hotelStarRating) {
this.hotelStarRating = hotelStarRating;
}
public void addAmenities(AmenityEntity amenityEntity){
if(amenitiesList==null){
amenitiesList = new ArrayList<>();
}
amenitiesList.add(amenityEntity);
}
#Override
public String toString() {
return "HotelEntity{" +
"hotelId=" + hotelId +
", hotelName='" + hotelName + '\'' +
", hotelDescription='" + hotelDescription + '\'' +
", hotelWebsite='" + hotelWebsite + '\'' +
", hotelPhoneNo=" + hotelPhoneNo +
", hotelEmail='" + hotelEmail + '\'' +
", hotelStarRating=" + hotelStarRating +
", addressEntity=" + addressEntity +
", categoryEntity=" + categoryEntity +
", amenitiesList=" + amenitiesList +
'}';
}
}
This is AddressEntity Class:
package com.springmvcweb.model;
import javax.persistence.*;
import java.io.Serializable;
#Entity
#Table(name = "ADDRESS", schema = "HOTEL")
public class AddressEntity implements Serializable {
private long addressId;
private String addressLine1;
private String addressLine2;
private String cityName;
private String stateName;
private String countryName;
private Long pincode;
#Id
#Column(name = "ADDRESS_ID")
public long getAddressId() {
return addressId;
}
public void setAddressId(long addressId) {
this.addressId = addressId;
}
#Basic
#Column(name = "ADDRESS_LINE1")
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
#Basic
#Column(name = "ADDRESS_LINE2")
public String getAddressLine2() {
return addressLine2;
}
public void setAddressLine2(String addressLine2) {
this.addressLine2 = addressLine2;
}
#Basic
#Column(name = "CITY_NAME")
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
#Basic
#Column(name = "STATE_NAME")
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
#Basic
#Column(name = "COUNTRY_NAME")
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
#Basic
#Column(name = "PINCODE")
public Long getPincode() {
return pincode;
}
public void setPincode(Long pincode) {
this.pincode = pincode;
}
}
Now I want to retrieve all those hotels filtered by their location(say cityname or statename) and I'm using query like this:
#Override
public List<HotelEntity> getHotelsByLocation(String location) {
try{
session = sessionFactory.getCurrentSession();
}catch (Exception e){
session = sessionFactory.openSession();
}
Query query = session.createQuery("from HotelEntity where HotelEntity.addressEntity.cityName " +
"like :location");
query.setParameter("location",location);
return query.getResultList();
}
Also I've used FetchType as EAGER in the HotelEntity OneToOne Mapping like this:
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "HOTEL_ADDRESS_ID")
public AddressEntity getAddressEntity() {
return addressEntity;
}
Right now it is giving me a null pointer exception. Please guide.
#OneToOne relationship is eagerly fetched anyway so adding that information is redundant.
Regarding the query I would form it like the following:
" select he from HotelEntity he
" inner join he.addressEntity ae"
" where ae.cityName like :location");

need to change default join column in One to Many and Many to One Mapping i n spring data jpa

I am using spring data jpa and want to change default join column happening between the entities. For example in the following mapping,
In Account.java,
#OneToMany(mappedBy = "account")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Invoice> invoices = new HashSet<>();
In Invoice.java
#ManyToOne
private Account account;
By default the id column of Account is getting joined with account_id of Invoice as per the given one to many and many to one mapping, which is also working fine for me. But now my requirement is instead of account_id in Invoice getting joined with id of Account, I want another field account_number of Invoice to be joined with id of Account, in my one to many and many to one mappings. Is it possible? As a trail I made the following change to my Invoice
#ManyToOne
#JoinColumn(name="account_number", nullable=false)
private Account account;
But I am getting the following error:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.trace.domain.Invoice column: account_number (should be mapped with insert="false" update="false")
Account.java
/**
* Account
*/
#Entity
#Table(name = "account")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Column(name = "number", nullable = false)
private String number;
#NotNull
#Column(name = "name")
private String name;
#Column(name = "currency_code")
private String currencyCode;
#Column(name = "edi_type")
private String ediType;
#Column(name = "is_fedex_express_gsr")
private Boolean isFedexExpressGsr;
#Column(name = "is_fedex_ground_gsr")
private Boolean isFedexGroundGsr;
#Column(name = "is_ups_gsr")
private Boolean isUpsGsr;
#Column(name = "electronic_voiding")
private Boolean electronicVoiding;
#Column(name = "activate_signature_service")
private Boolean activateSignatureService;
#Column(name = "reject_invoices")
private Boolean rejectInvoices;
#Column(name = "notify_client_services")
private Boolean notifyClientServices;
#Column(name = "is_active")
private Boolean isActive;
#Column(name = "address")
private String address;
#Column(name = "city")
private String city;
#Column(name = "state")
private String state;
#Column(name = "postal_code")
private String postalCode;
#OneToMany(mappedBy = "account")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Invoice> invoices = new HashSet<>();
#ManyToOne
private Courier courier;
#ManyToOne
private Client client;
#ManyToMany
#JoinTable(
name = "account_group_members",
joinColumns = {#JoinColumn(name = "account_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<AccountGroup> accountGroups = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCurrencyCode() {
return currencyCode;
}
public void setCurrencyCode(String currencyCode) {
this.currencyCode = currencyCode;
}
public String getEdiType() {
return ediType;
}
public void setEdiType(String ediType) {
this.ediType = ediType;
}
public Boolean getIsFedexExpressGsr() {
return isFedexExpressGsr;
}
public void setIsFedexExpressGsr(Boolean isFedexExpressGsr) {
this.isFedexExpressGsr = isFedexExpressGsr;
}
public Boolean getIsFedexGroundGsr() {
return isFedexGroundGsr;
}
public void setIsFedexGroundGsr(Boolean isFedexGroundGsr) {
this.isFedexGroundGsr = isFedexGroundGsr;
}
public Boolean getIsUpsGsr() {
return isUpsGsr;
}
public void setIsUpsGsr(Boolean isUpsGsr) {
this.isUpsGsr = isUpsGsr;
}
public Boolean getElectronicVoiding() {
return electronicVoiding;
}
public void setElectronicVoiding(Boolean electronicVoiding) {
this.electronicVoiding = electronicVoiding;
}
public Boolean getActivateSignatureService() {
return activateSignatureService;
}
public void setActivateSignatureService(Boolean activateSignatureService) {
this.activateSignatureService = activateSignatureService;
}
public Boolean getRejectInvoices() {
return rejectInvoices;
}
public void setRejectInvoices(Boolean rejectInvoices) {
this.rejectInvoices = rejectInvoices;
}
public Boolean getNotifyClientServices() {
return notifyClientServices;
}
public void setNotifyClientServices(Boolean notifyClientServices) {
this.notifyClientServices = notifyClientServices;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public Courier getCourier() {
return courier;
}
public void setCourier(Courier courier) {
this.courier = courier;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public Set<Invoice> getInvoices() {
return invoices;
}
public void setInvoices(Set<Invoice> invoices) {
this.invoices = invoices;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Account shipper = (Account) o;
if (!Objects.equals(id, shipper.id))
return false;
return true;
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Account{" + "id=" + id + ", number='" + number + "'" + ", name='" + name + "'" + ", currencyCode='"
+ currencyCode + "'" + ", ediType='" + ediType + "'" + ", isFedexExpressGsr='" + isFedexExpressGsr + "'"
+ ", isFedexGroundGsr='" + isFedexGroundGsr + "'" + ", isUpsGsr='" + isUpsGsr + "'"
+ ", electronicVoiding='" + electronicVoiding + "'" + ", activateSignatureService='"
+ activateSignatureService + "'" + ", rejectInvoices='" + rejectInvoices + "'"
+ ", notifyClientServices='" + notifyClientServices + "'" + ", isActive='" + isActive + "'"
+ ", address='" + address + "'" + ", city='" + city + "'" + ", state='" + state + "'" + ", postalCode='"
+ postalCode + "'" + '}';
}
}
Invoice.java
/**
* A Invoice.
*/
#Entity
#Table(name = "invoice")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Invoice implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "account_number")
private String accountNumber;
#Column(name = "invoice_number")
private String invoiceNumber;
#Column(name = "invoice_amount")
private Double invoiceAmount;
#Column(name = "status")
private String status;
#Column(name = "edi_number")
private String ediNumber;
#Column(name = "bill_date")
private Date billDate;
#Column(name = "courier_id")
private Long courierId;
#ManyToOne
#JoinColumn(name="account_number", nullable=true)
private Account account;
#OneToMany(mappedBy = "invoice")
//#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<InvoiceDetails> invoiceDetailss = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public String getInvoiceNumber() {
return invoiceNumber;
}
public void setInvoiceNumber(String invoiceNumber) {
this.invoiceNumber = invoiceNumber;
}
public Double getInvoiceAmount() {
return invoiceAmount;
}
public void setInvoiceAmount(Double invoiceAmount) {
this.invoiceAmount = invoiceAmount;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getEdiNumber() {
return ediNumber;
}
public void setEdiNumber(String ediNumber) {
this.ediNumber = ediNumber;
}
public Date getBillDate() {
return billDate;
}
public void setBillDate(Date billDate) {
this.billDate = billDate;
}
public Long getCourierId() {
return courierId;
}
public void setCourierId(Long courierId) {
this.courierId = courierId;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public Set<InvoiceDetails> getInvoiceDetailss() {
return invoiceDetailss;
}
public void setInvoiceDetailss(Set<InvoiceDetails> invoiceDetailss) {
this.invoiceDetailss = invoiceDetailss;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Invoice invoice = (Invoice) o;
if ( ! Objects.equals(id, invoice.id)) return false;
return true;
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Invoice{" +
"id=" + id +
", accountNumber='" + accountNumber + "'" +
", invoiceNumber='" + invoiceNumber + "'" +
", invoiceAmount='" + invoiceAmount + "'" +
", ediNumber='" + ediNumber + "'" +
", status='" + status + "'" +
", billDate='" + billDate + "'" +
", courierId='" + courierId + "'" +
'}';
}
}
As the error message says, there are two different mappings for the same column: account_number. And indeed, you have
#Column(name = "account_number")
private String accountNumber;
in your entity, which is redundant with the account field.
You just need to remove that field.

unbale to form proper join query in spring data jpa using #Query in Reporsitory

I am new to Spring Data Jpa and able to get the result using proper function names on a single table. But now I am facing problem to get the result based on join. I have two tables Invoice Table (columns : accountNumber, courierId), Account Table (columns : number, clinetId). Now I need to join these two tables and get Invoice results based on courierId and clientId. So in the repository I have formed the query as shown below:
#Query("select Invoice from Invoice i left join Account a on i.accountNumber = a.number where i.courierId=?1 and a.clientId=?2")
List<Invoice> findByCourierIdAndClientId(Long courierId, Long clientId);
But I am getting the following error in my debugging log:
[ERROR] org.hibernate.hql.internal.ast.ErrorCounter - Path expected for join!
[ERROR] org.hibernate.hql.internal.ast.ErrorCounter - Path expected for join!
antlr.SemanticException: Path expected for join!
[ERROR] org.hibernate.hql.internal.ast.ErrorCounter - Invalid path: 'a.clientId'
[ERROR] org.hibernate.hql.internal.ast.ErrorCounter - Invalid path: 'a.clientId'
org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'a.clientId'
[ERROR] org.hibernate.hql.internal.ast.ErrorCounter - left-hand operand of a binary operator was null
[ERROR] org.hibernate.hql.internal.ast.ErrorCounter - left-hand operand of a binary operator was null
antlr.SemanticException: left-hand operand of a binary operator was null
In Account Table I have client_id field in mysql table and in Account.java, I have
#ManyToOne
private Client client;
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
if I use the suggested solution,
#Query("SELECT i from Invoice i WHERE i.courierId =?1 AND i.clientId =?2")
List<Invoice> findByCourierIdAndClientId(Long courierId, Long clientId);
I am getting the following error:
java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: clientId of: com.trace.domain.Invoice [SELECT i from com.trace.domain.Invoice i WHERE i.courierId =?1 AND i.clientId =?2]
The following are my mappings:
In Account.java,
#OneToMany(mappedBy = "account")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Invoice> invoices = new HashSet<>();
And in Invoice.java,
#ManyToOne
private Account account;
Is there any changes I need to make in these mappings. Moreover in the solution
#Query("SELECT i from Invoice i WHERE i.courierId =?1 AND i.clientId =?2")
I don't follow how invoice table is gets only the joined details with Account, moreover there is no i.clientId in Invoice Table. clientId is present in Account Table only.
The following is my Invoice.java
/**
* A Invoice.
*/
#Entity
#Table(name = "invoice")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Invoice implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "account_number")
private String accountNumber;
#Column(name = "invoice_number")
private String invoiceNumber;
#Column(name = "invoice_amount")
private Double invoiceAmount;
#Column(name = "status")
private String status;
#Column(name = "edi_number")
private String ediNumber;
#Column(name = "bill_date")
private Date billDate;
#Column(name = "courier_id")
private Long courierId;
// #JoinColumn(name="owner_id", nullable=false)
#ManyToOne
private Account account;
#OneToMany(mappedBy = "invoice")
//#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<InvoiceDetails> invoiceDetailss = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public String getInvoiceNumber() {
return invoiceNumber;
}
public void setInvoiceNumber(String invoiceNumber) {
this.invoiceNumber = invoiceNumber;
}
public Double getInvoiceAmount() {
return invoiceAmount;
}
public void setInvoiceAmount(Double invoiceAmount) {
this.invoiceAmount = invoiceAmount;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getEdiNumber() {
return ediNumber;
}
public void setEdiNumber(String ediNumber) {
this.ediNumber = ediNumber;
}
public Date getBillDate() {
return billDate;
}
public void setBillDate(Date billDate) {
this.billDate = billDate;
}
public Long getCourierId() {
return courierId;
}
public void setCourierId(Long courierId) {
this.courierId = courierId;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public Set<InvoiceDetails> getInvoiceDetailss() {
return invoiceDetailss;
}
public void setInvoiceDetailss(Set<InvoiceDetails> invoiceDetailss) {
this.invoiceDetailss = invoiceDetailss;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Invoice invoice = (Invoice) o;
if ( ! Objects.equals(id, invoice.id)) return false;
return true;
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Invoice{" +
"id=" + id +
", accountNumber='" + accountNumber + "'" +
", invoiceNumber='" + invoiceNumber + "'" +
", invoiceAmount='" + invoiceAmount + "'" +
", ediNumber='" + ediNumber + "'" +
", status='" + status + "'" +
", billDate='" + billDate + "'" +
", courierId='" + courierId + "'" +
'}';
}
}
And the following is my Account.java,
/**
* Account.
*/
#Entity
#Table(name = "account")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Column(name = "number", nullable = false)
private String number;
#NotNull
#Column(name = "name")
private String name;
#Column(name = "currency_code")
private String currencyCode;
#Column(name = "edi_type")
private String ediType;
#Column(name = "is_fedex_express_gsr")
private Boolean isFedexExpressGsr;
#Column(name = "is_fedex_ground_gsr")
private Boolean isFedexGroundGsr;
#Column(name = "is_ups_gsr")
private Boolean isUpsGsr;
#Column(name = "electronic_voiding")
private Boolean electronicVoiding;
#Column(name = "activate_signature_service")
private Boolean activateSignatureService;
#Column(name = "reject_invoices")
private Boolean rejectInvoices;
#Column(name = "notify_client_services")
private Boolean notifyClientServices;
#Column(name = "is_active")
private Boolean isActive;
#Column(name = "address")
private String address;
#Column(name = "city")
private String city;
#Column(name = "state")
private String state;
#Column(name = "postal_code")
private String postalCode;
#OneToMany(mappedBy = "account")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Invoice> invoices = new HashSet<>();
#ManyToOne
private Courier courier;
#ManyToOne
private Client client;
#ManyToMany
#JoinTable(
name = "account_group_members",
joinColumns = {#JoinColumn(name = "account_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<AccountGroup> accountGroups = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCurrencyCode() {
return currencyCode;
}
public void setCurrencyCode(String currencyCode) {
this.currencyCode = currencyCode;
}
public String getEdiType() {
return ediType;
}
public void setEdiType(String ediType) {
this.ediType = ediType;
}
public Boolean getIsFedexExpressGsr() {
return isFedexExpressGsr;
}
public void setIsFedexExpressGsr(Boolean isFedexExpressGsr) {
this.isFedexExpressGsr = isFedexExpressGsr;
}
public Boolean getIsFedexGroundGsr() {
return isFedexGroundGsr;
}
public void setIsFedexGroundGsr(Boolean isFedexGroundGsr) {
this.isFedexGroundGsr = isFedexGroundGsr;
}
public Boolean getIsUpsGsr() {
return isUpsGsr;
}
public void setIsUpsGsr(Boolean isUpsGsr) {
this.isUpsGsr = isUpsGsr;
}
public Boolean getElectronicVoiding() {
return electronicVoiding;
}
public void setElectronicVoiding(Boolean electronicVoiding) {
this.electronicVoiding = electronicVoiding;
}
public Boolean getActivateSignatureService() {
return activateSignatureService;
}
public void setActivateSignatureService(Boolean activateSignatureService) {
this.activateSignatureService = activateSignatureService;
}
public Boolean getRejectInvoices() {
return rejectInvoices;
}
public void setRejectInvoices(Boolean rejectInvoices) {
this.rejectInvoices = rejectInvoices;
}
public Boolean getNotifyClientServices() {
return notifyClientServices;
}
public void setNotifyClientServices(Boolean notifyClientServices) {
this.notifyClientServices = notifyClientServices;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public Courier getCourier() {
return courier;
}
public void setCourier(Courier courier) {
this.courier = courier;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public Set<Invoice> getInvoices() {
return invoices;
}
public void setInvoices(Set<Invoice> invoices) {
this.invoices = invoices;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Account shipper = (Account) o;
if (!Objects.equals(id, shipper.id))
return false;
return true;
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Shipper{" + "id=" + id + ", number='" + number + "'" + ", name='" + name + "'" + ", currencyCode='"
+ currencyCode + "'" + ", ediType='" + ediType + "'" + ", isFedexExpressGsr='" + isFedexExpressGsr + "'"
+ ", isFedexGroundGsr='" + isFedexGroundGsr + "'" + ", isUpsGsr='" + isUpsGsr + "'"
+ ", electronicVoiding='" + electronicVoiding + "'" + ", activateSignatureService='"
+ activateSignatureService + "'" + ", rejectInvoices='" + rejectInvoices + "'"
+ ", notifyClientServices='" + notifyClientServices + "'" + ", isActive='" + isActive + "'"
+ ", address='" + address + "'" + ", city='" + city + "'" + ", state='" + state + "'" + ", postalCode='"
+ postalCode + "'" + '}';
}
}
After making the following entry in InvoiceRepository.java,
#Query("from Invoice i " + " where i.courierId = :courierId " + " and i.account.client.id = :clientId ")
List<Invoice> findByCourierIdAndClientId(#Param("courierId") Long courierId, #Param("clientId") Long clientId);
I am not getting any error but I am getting any result set from mysql database. My debugging log is as follows:
[DEBUG] com.sample.aop.logging.LoggingAspect - Enter: com.sample.web.rest.InvoiceResource.getInvoicesByCourierIdAndClientId() with argument[s] = [1, 1]
[DEBUG] com.sample.web.rest.InvoiceResource - REST request to get Invoices By Courier Id and Client Id 1 1
[DEBUG] com.sample.aop.logging.LoggingAspect - Enter: com.sample.service.InvoiceService.findByCourierIdAndClientId() with argument[s] = [1, 1]
[DEBUG] com.sample.aop.logging.LoggingAspect - Exit: com.sample.service.InvoiceService.findByCourierIdAndClientId() with result = []
[DEBUG] com.sample.aop.logging.LoggingAspect - Exit: com.sample.web.rest.InvoiceResource.getInvoicesByCourierIdAndClientId() with result = []
In InvoiceResource.java, I have the following mapping:
// Get Invoices By Courier Id and CustomerId
#RequestMapping(value = "/invoices/byCourierAndClient", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<Invoice> getInvoicesByCourierIdAndClientId(#RequestParam(value = "courierId") Long courierId,
#RequestParam(value = "clientId") Long clientId) {
log.debug("REST request to get Invoices By Courier Id and Client Id " + courierId + " " + clientId);
return invoiceService.findByCourierIdAndClientId(courierId, clientId);
}
The Id field in Client.java is as follows:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
The following query I have used to verify my data manually on mysql database tables which is returning result set containing on record.
select * from invoice i, account a where i.account_number = a.number
and i.courier_id = 1
and a.client_id = 1
A brief glance on your code seems suggested that you already have proper relationship mapping between Invoice and Account. In JPQL/HQL, you do not join like SQL by providing the join criteria. So your query should be
#Query("from Invoice i "
+ " where i.courierId = :courierId "
+ " and i.account.client.id = :clientId ")
List<Invoice> findByCourierIdAndClientId(#Param("courierId") Long courierId,
#Param("clientId") Long clientId);
(Assume the ID field in Client is called id)
Looks intuitive right?
And, given your query is really straight-forward, you can even let Spring Data generate your query by properly naming your finder method:
// no more #Query needed, works magically
List<Invoice> findByCourierIdAndAccountClientId(Long courierId, Long clientId);
You can try something like this. If you have the relation mapped correctly (#OneToMany/ManyToOne), you don't need to explicitly join the tables.
#Query("SELECT i from Invoice i WHERE i.courierId =?1 AND i.clientId =?2")
List<Invoice> findByCourierIdAndClientId(Long courierId, Long clientId);
You can even pass objects to a query directly, e.g.
#Query("SELECT i from Invoice i WHERE i.courierId= :courier AND i.clientId = :client")
List<Invoice> findByCourierAndClient(#Param("courier") Courier courier, #Param("client") Client client);

Resources