How to select specific fields and return the map as the result on a one to many query with spring data jpa? - spring-boot

There are two entities including Country and City whose relationship is one to many. The query result I want is a Map and child entity city as a Country field cityList should be also returned in one query, no N+1 query.
Entity code:
City
#Entity
#Data
#NoArgsConstructor
public class City {
private Integer cityId;
private String cityName;
private Timestamp lastUpdate;
#Id
#Column(name = "city_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getCityId() {
return cityId;
}
public void setCityId(int cityId) {
this.cityId = cityId;
}
#Basic
#Column(name = "city_name", nullable = true, length = 255)
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
#Basic
#Column(name = "last_update", nullable = true)
public Timestamp getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Timestamp lastUpdate) {
this.lastUpdate = lastUpdate;
}
}
Country
#Entity
public class Country {
private Integer countryId;
private String countryName;
private Timestamp lastUpdate;
private List<City> cityList;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "country_id", nullable = false)
public Integer getCountryId() {
return countryId;
}
public void setCountryId(int countryId) {
this.countryId = countryId;
}
#Basic
#Column(name = "country_name", nullable = true, length = 255)
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
#Basic
#Column(name = "last_update", nullable = true)
public Timestamp getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Timestamp lastUpdate) {
this.lastUpdate = lastUpdate;
}
#OneToMany
#JoinColumn(name = "country_id")
public List<City> getCityList() {
return cityList;
}
public void setCityList(List<City> cityList) {
this.cityList = cityList;
}
}
Repo
public interface CountryRepo extends JpaRepository<Country, Integer> {
#Query(value = "select new map(c.countryId as countryId , c.countryName as countryName , c.cityList as cityList) from Country c left join fetch c.cityList")
List findAllCountry3();
}
Expected result:
[
{
countryId: 1,
countryName: "China",
cityList: [
{
cityId: 1,
cityName: "Dalian",
lastUpdate: "2020-04-03T10:28:57.000+0000"
},
{
cityId: 2,
cityName: "Beijing",
lastUpdate: "2020-04-03T10:29:15.000+0000"
}
]
},
{
countryId: 2,
countryName: "US",
cityList: [
{
cityId: 3,
cityName: "New York",
lastUpdate: "2020-04-03T10:29:47.000+0000"
},
{
cityId: 4,
cityName: "Florda",
lastUpdate: "2020-04-03T10:30:05.000+0000"
}
]
},
{
countryId: 3,
countryName: "Japan",
cityList: [
{
cityId: 5,
cityName: "Tokyo",
lastUpdate: "2020-04-05T06:47:16.000+0000"
}
]
}
]
When I started spring boot, I got below error.
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=org.fxbird.entity.Country.cityList,tableName=city,tableAlias=citylist1_,origin=country country0_,columns={country0_.country_id ,className=org.fxbird.entity.City}}]
Any idea? Thanks

Related

incorrectly joining 2 entities in spring data jpa

#Entity
#Table(name = "product_table")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Product_id" , nullable = false, unique= true , length = 5)
private int ProductId;
#Column(name = "Product_Name" ,nullable = false , length = 50)
private String ProductName;
#Column(name = "Description" ,nullable = false , length = 200)
private String Description;
#Column(name ="Price" , nullable = false, unique= true , length = 5)
private Double Price;
#Column(name = "Discount" , nullable = false, unique= true , length = 5)
private Double Discount;
#Column(name ="Delivery_Charges" , nullable = false, unique= true , length = 5)
private Double DeliveryCharges;
#Column(name = "Avg_Rating",nullable = false, unique= true , length = 5)
private int AvgRating;
#Column(name = "Seller_Name",nullable = false, unique= true , length = 15)
private String SellerName;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Product_id", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private Cart Cart;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ProductId", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private WishList WishList;
public String getSellerName() {
return SellerName;
}
public void setSellerName(String sellerName) {
SellerName = sellerName;
}
public int getProductId() {
return ProductId;
}
public void setProductId(int productId) {
ProductId = productId;
}
public String getProductName() {
return ProductName;
}
public void setProductName(String productName) {
ProductName = productName;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public Double getPrice() {
return Price;
}
public void setPrice(Double price) {
Price = price;
}
public Double getDiscount() {
return Discount;
}
public void setDiscount(Double discount) {
Discount = discount;
}
public Double getDeliveryCharges() {
return DeliveryCharges;
}
public void setDeliveryCharges(Double deliveryCharges) {
DeliveryCharges = deliveryCharges;
}
public int getAvgRating() {
return AvgRating;
}
public void setAvgRating(int avgRating) {
AvgRating = avgRating;
}
}
#Entity
#Table(name = "Cart_table")
public class Cart {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Cart_Id" , nullable = false, unique = true, length = 5)
private int CartId;
#Column(name = "Product_Name" , nullable = false, length = 50)
private String ProductName;
#Column(name = "Seller_Name" , nullable = false,length = 15)
private String SellerName;
#Column(name = "Quantity" , nullable = false)
private int Quantity;
#Column(name = "Cart_Offer_Price" , unique = true)
private Double CartOfferPrice;
#Column(name = "Product_id" , nullable = false, unique = true, length = 5)
private int ProductId;
public int getProductId() {
return ProductId;
}
public void setProductId(int productId) {
ProductId = productId;
}
#OneToOne(targetEntity = Product.class, mappedBy = "Cart", orphanRemoval = false, fetch = FetchType.LAZY)
private Product product;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Cart_Id", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private OrdersCartMapping OrdersCartMapping;
public int getCartId() {
return CartId;
}
public void setCartId(int cartId) {
CartId = cartId;
}
public String getProductName() {
return ProductName;
}
public void setProductName(String productName) {
ProductName = productName;
}
public String getSellerName() {
return SellerName;
}
public void setSellerName(String sellerName) {
SellerName = sellerName;
}
public int getQuantity() {
return Quantity;
}
public void setQuantity(int quantity) {
Quantity = quantity;
}
public Double getCartOfferPrice() {
return CartOfferPrice;
}
public void setCartOfferPrice(Double cartOfferPrice) {
CartOfferPrice = cartOfferPrice;
}
}
#Repository
public interface CartRepository extends JpaRepository<Cart , Integer> {
#Query("SELECT new com.megamartonline.dto.CartProductDto(c.ProductName,c.CartOfferPrice,c.Quantity , p.Price ,p.Discount,p.DeliveryCharges,c.CartId ) "
+ "FROM Cart c INNER JOIN c.product p")
List<CartProductDto> fetchProductCartDataInnerJoin();
}
Here i m trying to join Product with Cart using Product_id column but when i test my repository method it is incorrectly joining as below
select
cart0_.product_name as col_0_0_,
cart0_.cart_offer_price as col_1_0_,
cart0_.quantity as col_2_0_,
product1_.price as col_3_0_,
product1_.discount as col_4_0_,
product1_.delivery_charges as col_5_0_
from
cart_table cart0_
inner join
product_table product1_
on cart0_.cart_id=product1_.product_id
please help , what i am doing wrong here.
Here i m trying to join 2 Product with Cart using Product_id column but when i test my repository method it is incorrectly joining.
In Product, instead of productId, you have to declare the join to JPA in the entity this way:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Product_id")
private Product Product;
Hibernate now knows how to handle the join.
You can't use both an ID column and a JoinColumn; it won't know which one to use, so you should remove productId.
I suggest a #ManyToOne because the #OneToOne join you are using seems strange for a cart. Usually a cart has multiple (many) products.
You can easily change the fetch type from lazy to eager

Error mapping OneToMany or ManyToOne unmapped class

I have this problem :
Error creating bean with name 'ICustomerDao' defined in com.biblio.fr.biblio.repository.ICustomerDao defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: com.biblio.fr.biblio.entite.Book.loans[com.biblio.fr.biblio.entite.Loan]
this is my code :
#Entity
#Table(name = "BOOK")
public class Book {
private Integer id;
private String title;
private String isbn;
private LocalDate releaseDate;
private LocalDate registerDate;
private Integer totalExamplaries;
private String author;
private Category category;
Set<Loan> loans = new HashSet<Loan>();
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "BOOK_ID")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "TITLE", nullable = false)
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Column(name = "ISBN", nullable = false, unique = true)
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
#Column(name = "RELEASE_DATE", nullable = false)
public LocalDate getReleaseDate() {
return releaseDate;
}
public void setReleaseDate(LocalDate releaseDate) {
this.releaseDate = releaseDate;
}
#Column(name = "REGISTER_DATE", nullable = false)
public LocalDate getRegisterDate() {
return registerDate;
}
public void setRegisterDate(LocalDate registerDate) {
this.registerDate = registerDate;
}
#Column(name = "TOTAL_EXAMPLARIES")
public Integer getTotalExamplaries() {
return totalExamplaries;
}
public void setTotalExamplaries(Integer totalExamplaries) {
this.totalExamplaries = totalExamplaries;
}
#Column(name = "AUTHOR")
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
#ManyToOne(optional = false)
#JoinColumn(name = "CAT_CODE", referencedColumnName = "CODE")
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
// #OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.book", cascade =
// CascadeType.ALL)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk", cascade = CascadeType.ALL)
public Set<Loan> getLoans() {
return loans;
}
public void setLoans(Set<Loan> loans) {
this.loans = loans;
}
}
public class Loan implements Serializable {
private static final long serialVersionUID = 144293603488149743L;
private LoanId pk = new LoanId();
private LocalDate beginDate;
private LocalDate endDate;
private LoanStatus status;
#EmbeddedId
public LoanId getPk() {
return pk;
}
public void setPk(LoanId pk) {
this.pk = pk;
}
#Column(name = "BEGIN_DATE", nullable = false)
public LocalDate getBeginDate() {
return beginDate;
}
public void setBeginDate(LocalDate beginDate) {
this.beginDate = beginDate;
}
#Column(name = "END_DATE", nullable = false)
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
#Enumerated(EnumType.STRING)
#Column(name = "STATUS")
public LoanStatus getStatus() {
return status;
}
public void setStatus(LoanStatus status) {
this.status = status;
}
}
#Embeddable
public class LoanId implements Serializable {
private static final long serialVersionUID = 3912193101593832821L;
private Book book;
private Customer customer;
private LocalDateTime creationDateTime;
public LoanId() {
super();
}
public LoanId(Book book, Customer customer) {
super();
this.book = book;
this.customer = customer;
this.creationDateTime = LocalDateTime.now();
}
#ManyToOne
public Book getBook() {
return book;
}
public void setBook(Book bbok) {
this.book = bbok;
}
#ManyToOne
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
#Column(name = "CREATION_DATE_TIME")
public LocalDateTime getCreationDateTime() {
return creationDateTime;
}
public void setCreationDateTime(LocalDateTime creationDateTime) {
this.creationDateTime = creationDateTime;
}
}
#Table(name = "CUSTOMER")
public class Customer {
private Integer id;
private String firstName;
private String lastName;
private String job;
private String address;
private String email;
private LocalDate creationDate;
Set<Loan> loans = new HashSet<Loan>();
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CUSTOMER_ID")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "FIRST_NAME", nullable = false)
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name = "LAST_NAME", nullable = false)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Column(name = "JOB")
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
#Column(name = "ADDRESS")
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
#Column(name = "EMAIL", nullable = false, unique = true)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "CREATION_DATE", nullable = false)
public LocalDate getCreationDate() {
return creationDate;
}
public void setCreationDate(LocalDate creationDate) {
this.creationDate = creationDate;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.customer", cascade = CascadeType.ALL)
public Set<Loan> getLoans() {
return loans;
}
public void setLoans(Set<Loan> loans) {
this.loans = loans;
}
}
public class Category {
public Category() {
}
public Category(String code, String label) {
super();
this.code = code;
this.label = label;
}
private String code;
private String label;
#Id
#Column(name = "CODE")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#Column(name = "LABEL", nullable = false)
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
#Repository
public interface ICategoryDao extends JpaRepository<Category, Integer> {
}
public interface ICustomerDao extends JpaRepository<Customer, Integer> {
public Customer findCustomerByEmailIgnoreCase(String email);
public List<Customer> findCustomerByLastNameIgnoreCase(String lastName);
}
I can't see where is the problem of my oneTomany annotation
Anyone can, i help me.

POST request with Many-to-many relationship in Spring Data REST

I'm trying to add a movie to MySQL database, here's my database schema:
Movie(id, name)
Genre(id, name)
Movie_genre(id_movie, id_genre)
And here's my model classes:
Movie.ts
public class Movie {
private Short id;
private String name;
private List<MovieGenre> movieGenres;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
public Short getId() {
return id;
}
public void setId(Short id) {
this.id = id;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "movie")
public List<MovieGenre> getMovieGenres() {
return movieGenres;
}
public void setMovieGenres(List<MovieGenre> movieGenres) {
this.movieGenres = movieGenres;
}
}
Genre.ts
public class Genre {
private Short id;
private String name;
private List<MovieGenre> movieGenres;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
public Short getId() {
return id;
}
public void setId(Short id) {
this.id = id;
}
#Column(name = "name", nullable = false, length = 15)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "genre")
#JsonIgnore
public List<MovieGenre> getMovieGenres() {
return movieGenres;
}
public void setMovieGenres(List<MovieGenre> movieGenres) {
this.movieGenres = movieGenres;
}
}
MovieGenre.ts ( that model stands for the generated table )
public class MovieGenre {
private MovieGenrePK id;
private Movie movie;
private Genre genre;
#EmbeddedId
#JsonIgnore
public MovieGenrePK getId() {
return id;
}
public void setId(MovieGenrePK id) {
this.id = id;
}
#MapsId("movieId")
#ManyToOne
#JoinColumn(name = "movie_id", referencedColumnName = "id", nullable = false)
#JsonIgnore
public Movie getMovie() {
return movie;
}
public void setMovie(Movie movie) {
this.movie = movie;
}
#MapsId("genreId")
#ManyToOne
#JoinColumn(name = "genre_id", referencedColumnName = "id", nullable = false)
public Genre getGenre() {
return genre;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
}
and because we have composite key in the last model, we need a class for that :
public class MovieGenrePK implements Serializable {
private Short movieId;
private Short genreId;
#Column(name = "movie_id", nullable = false)
public Short getMovieId() {
return movieId;
}
public void setMovieId(Short movieId) {
this.movieId = movieId;
}
#Column(name = "genre_id", nullable = false)
public Short getGenreId() {
return genreId;
}
public void setGenreId(Short genreId) {
this.genreId = genreId;
}
}
So I'm trying to add a movie with genres by making a post request, first i made a post request for adding a movie and another one for adding a genre, that's works fine, now i need to associate a genre to a movie.
I tried the following:
I made a POST request to the following endpoint: http://localhost:8080/api/movieGenres with application/json header and with the following body:
{
"movie": "http://localhost:8080/api/movies/6",
"genre": "http://localhost:8080/api/genres/1"
}
but i got the error:
{
"timestamp": "2018-08-22T21:10:30.830+0000",
"status": 500,
"error": "Internal Server Error",
"message": "NullPointerException occurred while calling setter of com.movies.mmdbapi.model.MovieGenrePK.genreId; nested exception is org.hibernate.PropertyAccessException: NullPointerException occurred while calling setter of com.movies.mmdbapi.model.MovieGenrePK.genreId",
"path": "/api/movieGenres"
}
You have to instatiate MovieGenrePK, change:
public class MovieGenre {
private MovieGenrePK id;
}
to
public class MovieGenre {
private MovieGenrePK id = new MovieGenrePK();
}

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

JPA #OneToMany get latest record by date from Join

Getting stuck trying to fetch the latest record from a Join
I have the following classes
Author
#Entity
#Table(name = "author")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#OneToMany
#JoinColumn(name = "author_id", referencedColumnName = "id")
#OrderBy("id Desc")
private List<Book> books;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
}
Book
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "author_id")
private Integer authorId;
#Column(name = "date_published")
private Date datePublished;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Integer getAuthorId() {
return authorId;
}
public void setAuthorId(Integer authorId) {
this.authorId = authorId;
}
public Date getDatePublished() {
return datePublished;
}
public void setDatePublished(Date datePublished) {
this.datePublished = datePublished;
}
}
Repository
#Repository
public interface AuthorRepository extends
JpaRepository<Author, Long> {
public Page<Author> findALL(int id, Pageable pageable);
}
Current results
{
"id": 1,
"name": "James",
"books":[
{
"id": 1,
"name": "book1",
"datePublished": '12/12/2012'
},
{
"id": 1,
"name": "book2",
"datePublished": '01/02/2013'
}]
},
{
"id": 2,
"name": "Tim",
"books":[
{
"id": 5,
"name": "book5",
"datePublished": '12/12/2014'
},{
"id": 6,
"name": "book6",
"datePublished": '01/02/2015'
}]
}
Expected Result
{
"id": 1,
"name": "James",
"books":[
{
"id": 1,
"name": "book2",
"datePublished": '01/02/2013'
}]
},
{
"id": 2,
"name": "Tim",
"books":[
{
"id": 6,
"name": "book6",
"datePublished": '01/02/2015'
}]
}
From this a list of Authors are being returned with all their respective books.
Question is how can JPA assist me to pick only the latest book from the collection based on date published.
If you are using hibernate you can achieve this using #JoinFormula to map the latest record by date. Something like:
#ManyToOne(fetch = FetchType.LAZY)
#JoinFormula("(" +
"SELECT b.id " +
"FROM book b " +
"WHERE b.author_id = id " +
"ORDER BY b.date_published DESC " +
"LIMIT 1" +
")")
private Book latestBook;
I had similar problem. The other solution is with #Where annotation:
#OneToMany
#JoinColumn(name = "author_id", referencedColumnName = "id")
#Where(clause = "date_published = (SELECT MAX(book.date_published) " +
"FROM book" +
"where author_id = book.author_id)")
#OrderBy("datePublished Desc")
private List<Book> books;
My post on stack: Get applications with their latest status only
if you want to get last book for each author , you can add transient field to get it :
#Entity
#Table(name = "author")
public class Author {
.......
#Transient
private Book lastBook;
#PostLoad
private void setLastBook() {
if(books==null || books,isEmpty())
this.lastBook=null;
}else{
this.lastBook=books.get(0);
}
}
or make it one to one and save it in db by same method annotated with #PostPersist and #PostUpdate. it will save in db automatically last book
the answer by #Seldo97 is correct, but he missed the space between "book" and "where" in the Select query, which will throw an error.
so basically it should be
#OneToMany
#JoinColumn(name = "author_id", referencedColumnName = "id")
#Where(clause = "date_published = (SELECT MAX(book.date_published) " +
"FROM book" +
" where author_id = book.author_id)")
#OrderBy("datePublished Desc")
private List<Book> books;
author_id -> basically refers to foreign key column name in the child.
entity
date_published -> this refers to the column by which we want to
sort(in this case the date column name).
so, the above query will take the record with the latest date and put it in the list object:
List<book> book;

Resources