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

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.

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 can I fetch data from 2 tables using HQL having one to many association with each other?

I have 2 tables in my database, city and hotel_details. Primary key of city is foreign key in hotel_details and associated with one to many association. I want to fetch data(status,registration,etc..) from hotel_details based on city_id and hotel_name by calling getAvailabilityStatus from my controller. Following is my code :
City Entity class
#Entity
#Table(name="city")
public class City {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="city_name")
private String cityName;
#OneToMany(mappedBy="city",
cascade= {CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.DETACH, CascadeType.REFRESH})
private List<HotelDetails> hotelDetails;
public City() {
}
public List<HotelDetails> getHotelDetails() {
return hotelDetails;
}
public void setHotelDetails(List<HotelDetails> hotelDetails) {
this.hotelDetails = hotelDetails;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
#Override
public String toString() {
return "City [id=" + id + ", cityName=" + cityName + "]";
}
}
2.HotelDetails Entity class
#Entity
#Table(name="hotel_details")
public class HotelDetails {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#ManyToOne(cascade= {CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.DETACH, CascadeType.REFRESH})
#JoinColumn(name="city_id")
private City city;
#Column(name="hotel_name")
private String hotelName;
#Column(name="available_date")
#DateTimeFormat(pattern = "dd/MM/yyyy")
private Date availableDate;
#Column(name="price")
private int price;
#Column(name="gst")
private int gst;
#Column(name="status")
private int status;
#Column(name="room_type")
private String roomType;
public HotelDetails() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
public String getHotelName() {
return hotelName;
}
public void setHotelName(String hotelName) {
this.hotelName = hotelName;
}
public Date getAvailableDate() {
return availableDate;
}
public void setAvailableDate(Date availableDate) {
this.availableDate = availableDate;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getGst() {
return gst;
}
public void setGst(int gst) {
this.gst = gst;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getRoomType() {
return roomType;
}
public void setRoomType(String roomType) {
this.roomType = roomType;
}
#Override
public String toString() {
return "HotelDetails [id=" + id + ", hotelName=" + hotelName + ", availableDate=" + availableDate + ", price="
+ price + ", gst=" + gst + ", status=" + status + ", roomType=" + roomType + "]";
}
}
3.HotelDAOImpl
#Component
#Repository
public class HotelDetailsDAOImpl implements HotelDetailsDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional
public Set<String> getHotels() {
Session currentSession = sessionFactory.getCurrentSession();
Query theQuery2 = currentSession.createQuery("Select h.hotelName from HotelDetails h");
List<String> listHotels = theQuery2.list();
Set<String> hotels = new HashSet<String>(listHotels);
return hotels;
}
#Override
#Transactional
public List<City> getAvailabilityStatus(int cityID, String hotelName, String cityName) {
Session currentSession = sessionFactory.getCurrentSession();
Query theQuery4 = currentSession.createQuery("...");
//theQuery4.setParameter("hotelName", hotelName);
//List<City> cities = theQuery4.list();
return cities;
}
}
String jpql = "select c from City c join c.hotelDetails h where h.hotelName = :hotelName";
or
String jpql = "select c from HotelDetails h join h.city c where h.hotelName = :hotelName";
and then
Query theQuery4 = currentSession.createQuery(jpql);
theQuery4.setParameter("hotelName", hotelName);
List<City> cities = theQuery4.list();
This is just an example, but once you have defined the join and the entity aliases correctly, you can refer to entity attributes in the WHERE clause any way you prefer.
For example:
jpql += " AND c.id=:id AND h.price<:price AND h.availableDate BETWEEN :start AND :end";
same for the select clause, you can use all the combinations of:
"select c.cityName, h.status, ..."
"select c, h from ..."
Check the Hibernate ORM query for many examples of how you can use JPQL/HQL.

Spring JPA - A different object with the same identifier value was already

I have 3 classes :
#Entity
public class Purchase {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id ;
private String description ;
private float discount ; //percentage
private boolean status ; // paid or not
#ManyToOne
#JoinColumn(name = "company_id")
#JsonIgnore
private Company company ;
#ManyToOne
#JoinColumn(name = "BusinnesPartner_id")
#JsonIgnore
private BusineesPartner busineesPartner ;
#OneToMany(mappedBy = "purchase", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<PurchaseItem> purchaseItems;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public float getDiscount() {
return discount;
}
public void setDiscount(float discount) {
this.discount = discount;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public BusineesPartner getBusineesPartner() {
return busineesPartner;
}
public void setBusineesPartner(BusineesPartner busineesPartner) {
this.busineesPartner = busineesPartner;
}
public Set<PurchaseItem> getPurchaseItems() {
return purchaseItems;
}
public void setPurchaseItems(Set<PurchaseItem> purchaseItems) {
this.purchaseItems = purchaseItems;
}
public Purchase() {
super();
// TODO Auto-generated constructor stub
}
#Override
public String toString() {
return "Purchase [id=" + id + ", description=" + description + ", discount=" + discount + ", status=" + status
+ ", company=" + company + ", busineesPartner=" + busineesPartner + ", purchaseItems=" + purchaseItems
+ "]";
}
}
And item :
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id ;
private String name ;
private String brand ;
private String category ;
private Double unitPrice ;
private Double weight ;
private String manufacturer ;
private String description ;
#ManyToOne
#JoinColumn(name = "company_id")
private Company company ;
#OneToMany(mappedBy = "item")
private Set<ItemInventory> itemInventories;
#OneToMany(mappedBy = "item")
private Set<PurchaseItem> purchaseItems;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public Double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(Double unitPrice) {
this.unitPrice = unitPrice;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<ItemInventory> getItemInventories() {
return itemInventories;
}
public void setItemInventories(Set<ItemInventory> itemInventories) {
this.itemInventories = itemInventories;
}
#Override
public String toString() {
return "Item [id=" + id + "]";
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public Set<PurchaseItem> getPurchaseItems() {
return purchaseItems;
}
public void setPurchaseItem(Set<PurchaseItem> purchaseItems) {
this.purchaseItems = purchaseItems;
}
public Item(Integer id, String name, String brand, String category, Double unitPrice, Double weight,
String manufacturer, String description, Company company, Set<ItemInventory> itemInventories,
Set<PurchaseItem> purchaseItems) {
super();
this.id = id;
this.name = name;
this.brand = brand;
this.category = category;
this.unitPrice = unitPrice;
this.weight = weight;
this.manufacturer = manufacturer;
this.description = description;
this.company = company;
this.itemInventories = itemInventories;
this.purchaseItems = purchaseItems;
}
public Item() {
}
}
And PurchaseItem :
#Entity
#Table(name = "purchase_item")
public class PurchaseItem implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "item_id")
private Item item ;
#Id
#ManyToOne
#JoinColumn(name = "purchase_id")
private Purchase purchase ;
private Long quantity ;
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public Purchase getPurchase() {
return purchase;
}
public void setPurchase(Purchase purchase) {
this.purchase = purchase;
}
public Long getQuantity() {
return quantity;
}
public void setQuantity(Long quantity) {
this.quantity = quantity;
}
public PurchaseItem(Item item, Purchase purchase, Long quantity) {
super();
this.item = item;
this.purchase = purchase;
this.quantity = quantity;
}
public PurchaseItem() {
super();
// TODO Auto-generated constructor stub
}
#Override
public String toString() {
return "PurchaseItem [item=" + item + ", purchase=" + purchase + ", quantity=" + quantity + "]";
}
}
And here is my controller :
#RestController
public class PurchaseController {
#Autowired
private ItemRepository itemRepos ;
#Autowired
private InventoryRepository inventoryRepos ;
#Autowired
private CompanyRepository companyRepos ;
#Autowired
private PurchaseRepository purchaseRepos ;
#RequestMapping(value = "purchase/add/{company}", method = RequestMethod.POST)
public Object addItem(#RequestBody Purchase purchase) {
Purchase newPurchase = new Purchase() ;
newPurchase.setDiscount(purchase.getDiscount());
newPurchase.setStatus(purchase.isStatus());
newPurchase.setBusineesPartner(purchase.getBusineesPartner()) ;
newPurchase.setDescription(purchase.getDescription()) ;
newPurchase.setPurchaseItems(new HashSet<PurchaseItem>());
newPurchase = purchaseRepos.save(newPurchase) ;
for(PurchaseItem curentPurchaseItem : purchase.getPurchaseItems()) {
Item item = itemRepos.findOne(curentPurchaseItem.getItem().getId()) ;
curentPurchaseItem.setPurchase(newPurchase);
curentPurchaseItem.setItem(item);
newPurchase.getPurchaseItems().add(curentPurchaseItem) ;
}
return purchaseRepos.save(newPurchase) ;
}
}
Here is the error Stack :
A different object with the same identifier value was already
associated with the session :
[com.inconso.models.PurchaseItem#PurchaseItem [item=null,
purchase=null, quantity=25]]; nested exception is
javax.persistence.EntityExistsException: A different object with the
same identifier value was already associated with the session :
[com.inconso.models.PurchaseItem#PurchaseItem [item=null,
purchase=null, quantity=25]]

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");

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