I am trying to make a one to many and many to one relation in hibernate and spring.
below is my code for product class
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="Product")
public class Product implements Serializable{
#Id
#Column(name="productId")
#GeneratedValue
private Integer productId;
#Column(name="productName")
private String productName;
#Column(name="productPrice")
private int productPrice;
//---------------------------------------item mapped to category------------------------------------------//
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(
name="CategoryProduct",
joinColumns= #JoinColumn(name="productId")
)
private Category category;
//--------------------------------------------------------------------------------------------------------//
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public int getProductPrice() {
return productPrice;
}
public void setProductPrice(int productPrice) {
this.productPrice = productPrice;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
below is my code for category class
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Table(name="Category")
public class Category implements Serializable{
#Id
#Column(name="categoryId")
#GeneratedValue
private Integer categoryId;
#Column(name="categoryName")
private String categoryName;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinTable(
name="CategoryProduct",
joinColumns = #JoinColumn(name="categoryId"),
inverseJoinColumns = #JoinColumn(name="productId")
)
public Set<Product> product;
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Set<Product> getProduct() {
return product;
}
public void setProduct(Set<Product> product) {
this.product = product;
}
}
Whenever i run the code i am getting Invalid column name 'category_categoryId'.
Structure of my tables
Product has column as productId, poductName and productPrice
category has columns as categoryId, categoryName
categoryproducts has columns as categoryId and productId
you forgot to put inverseJoinColumns at your #JoinTable in Product Class. This cause hibernate to use their convention of joinTable which is <ClassName>_<columnName>. Change it to
#JoinTable(
name="CategoryProduct",
joinColumns = #JoinColumn(name="productId"),
inverseJoinColumns = #JoinColumn(name="categoryId")
)
private Category category;
However, seeing at your design, you are actually creating 2 uni-directional association between product and category. If you want to create bi-directional association, I suggest you change the One side (Category), to use mappedBy
#OneToMany(mappedBy="category", cascade=CascadeType.ALL,fetch=FetchType.EAGER)
public Set<Product> product;
It will generally achieve the same result. Hope it helps!
Related
I am trying to implement one entity to see how Auditing works in spring. I have tow issues here:
First issue is that "created_by" field is always set to null in the database, although I have created a bean of AuditAware and set it to myself.
Second issue is that whenever I want to insert something into the country table, it forces me to provide the version number. It is not the behaviour I want as I expect version gets picked up by the spring itself
I appreciate if someone could help me to tackle these two issues.
AbstractMethodEntity is as follow:
package com.xx.xxx.hotel;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
#MappedSuperclass
#EntityListeners({ AuditingEntityListener.class })
public abstract class AbstractModelEntity<U> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "created_by")
#CreatedBy
private U CreatedBy;
#Column(name = "create_date")
#CreatedDate
private LocalDateTime createdDate;
#Version
private long version;
#Column(name = "modified_by")
#LastModifiedBy
private U lastModifiedBy;
#Column(name = "modified_date")
#LastModifiedDate
private LocalDateTime lastModifiedDate;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public U getCreatedBy() {
return CreatedBy;
}
public void setCreatedBy(U createdBy) {
CreatedBy = createdBy;
}
public LocalDateTime getCreatedDate() {
return createdDate;
}
public void setCreatedDate(LocalDateTime createdDate) {
this.createdDate = createdDate;
}
public U getLastModifiedBy() {
return lastModifiedBy;
}
public void setLastModifiedBy(U lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public LocalDateTime getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(LocalDateTime lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
}
The Country entity:
package com.xx.xxx.hotel.service.country;
import com.miraftabi.hossein.hotel.AbstractModelEntity;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Audited
#AuditOverride(forClass = AbstractModelEntity.class, isAudited = true)
#Table(name = "country")
public class CountryEntity extends AbstractModelEntity<String> {
#Column(name = "name", nullable = false)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
AuditAwareImpl file:
package com.xx.xxx.hotel.service;
import org.springframework.data.domain.AuditorAware;
import java.util.Optional;
public class AuditorAwareImpl implements AuditorAware<String> {
#Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Hossein");
}
}
AuditConfiguraiton file:
package com.xx.xxx.hotel.config;
import com.xx.xxx.hotel.service.AuditorAwareImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
#Configuration
#EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class AuditConfiguration {
#Bean
public AuditorAware<String> auditorAware() {
return new AuditorAwareImpl();
}
}
RepositoryConfiguration file:
package com.xx.xxx.hotel.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
public class RepositoryConfiguration {
}
CountryRevisionRepository file:
package com.xx.xxx.hotel.service.country;
import org.springframework.data.repository.history.RevisionRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CountryRevisionRepository extends RevisionRepository<CountryEntity, Long, Integer> {
}
Application.properties:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/hotel
spring.datasource.username=${DATABASE_USERNAME}
spring.datasource.password=${DATABASE_PASSWORD}
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
I have stuck on dealing with DB by using hibernate orm in spring mvc environment.
I have some tables; but I'm not gonna tell you my tables(If you want, I will edit this post)
The problem is that when hibernate runs, it generates sql - I can see the sql by configuring "hbm2_ddl auto" - but the sql has invalid identifier.
select newsreplie0_.news_article# as news6_3_4_, newsreplie0_.reply# as reply1_4_,
newsreplie0_.reply# as reply1_4_3_, newsreplie0_.account_account# as account5_4_3_,
newsreplie0_.content as content4_3_, newsreplie0_.dt as dt4_3_,
newsreplie0_.news_article# as news6_4_3_, newsreplie0_.reply_at as reply4_4_3_,
account1_.account# as account1_0_0_, account1_.email as email0_0_,
account1_.passwd as passwd0_0_, accountpro2_.account# as account1_1_1_,
accountpro2_.nickname as nickname1_1_, accountsec3_.account# as account1_2_2_,
accountsec3_.activate_key as activate2_2_2_, accountsec3_.activated as activated2_2_,
accountsec3_.enabled as enabled2_2_, accountsec3_.login_failed as login5_2_2_
from news_reply newsreplie0_
left outer join
cookingstep.account account1_ on newsreplie0_.account_account#=account1_.account#
left outer join
cookingstep.account_profile accountpro2_ on account1_.account#=accountpro2_.account#
left outer join
cookingstep.account_security accountsec3_ on account1_.account#=accountsec3_.account#
where newsreplie0_.news_article#=9
{FAILED after 4 msec}
The above statement is a sql generated by hibernate. And the error is:
java.sql.SQLSyntaxErrorException:
ORA-00904: "NEWSREPLIE0_"."ACCOUNT_ACCOUNT#": Invalid Identifier
In that exception message, there is a column called "ACCOUNT_ACCOUNT#".
It should be just "ACCOUNT#", not following "ACCOUNT_".
So, how to remove the word ?
EDIT:
Thank you all for your reply. I have asked similar question before.
And I checked out that article, it seems the problem was #JoinColumn annotation missing. Now it works out.
Here is my Entities.
Account.java for user information
package com.musicovery12.cookingstep.persistence.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
#Entity
#Table(name="account", catalog="cookingstep", uniqueConstraints= {
#UniqueConstraint(columnNames="email")
})
public class Account implements Serializable{
private static final long serialVersionUID = 1L;
private int accountId;
private String email;
private String password;
private Set<UserRole> userRoles = new HashSet<UserRole>(0);
private AccountProfile profile;
private AccountSecurity security;
private Set<News> newsList;
private Set<NewsReply> newsReplyList;
public Account() {}
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_account")
#SequenceGenerator(name="seq_account", sequenceName="seq_account", allocationSize=1)
#Column(name="account#", unique=true, nullable=false)
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
#Column(name="email", unique=true, nullable=false)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name="passwd", nullable=false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#OneToMany(mappedBy="pk.account", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
#OneToOne(mappedBy="account", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public AccountProfile getProfile() {
return profile;
}
public void setProfile(AccountProfile profile) {
this.profile = profile;
}
#OneToOne(mappedBy="account", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public AccountSecurity getSecurity() {
return security;
}
public void setSecurity(AccountSecurity security) {
this.security = security;
}
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<News> getNewsList() {
return newsList;
}
public void setNewsList(Set<News> newsList) {
this.newsList = newsList;
}
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<NewsReply> getNewsReplyList() {
return newsReplyList;
}
public void setNewsReplyList(Set<NewsReply> newsReplyList) {
this.newsReplyList = newsReplyList;
}
}
and NewsReply.java for news community article's reply list.
package com.musicovery12.cookingstep.persistence.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name="news_reply")
public class NewsReply {
private int replyId;
private News news;
private Date date;
private String content;
private Account account;
private int replyAt;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="gen_seq")
#SequenceGenerator(name="gen_seq", sequenceName="gen_seq", allocationSize=1)
#Column(name="reply#", unique=true, nullable=false)
public int getReplyId() {
return replyId;
}
public void setReplyId(int replyId) {
this.replyId = replyId;
}
#Temporal(TemporalType.DATE)
#Column(name="dt")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
#Column(name="content", nullable=false)
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#Column(name="reply_at")
public int getReplyAt() {
return replyAt;
}
public void setReplyAt(int replyAt) {
this.replyAt = replyAt;
}
#ManyToOne
public News getNews() {
return news;
}
public void setNews(News news) {
this.news = news;
}
#ManyToOne
#JoinColumn(name="account#", referencedColumnName="account#")
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
in NewsReply.java, there was no JoinColumn annotation to point foreing key column name.
Thank you.
#ManyToOne
#JoinColumn(name="account#", referencedColumnName="account#")
public Account getAccount() {
return account;
}
This is the problem, you tell hibernate the table has a technical name of account# what is not allowed.
What you can do is to force hibernate to use that # by defining
#ManyToOne
#JoinColumn(name="`account#`", referencedColumnName="`account#`")
public Account getAccount() {
return account;
}
But this is bad style and you have to do it on the owning-side too.
Why dont you let hibernate create the entitys for you? He is much more precisly!
Hi all i have a small issue with joining two tables using jparepository using #query but i am getting error. please help me with this.
UserAddress.java
package com.surya_spring.example.Model;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
#Entity
#Table(name = "user_address")
//#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class UserAddress implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3570928575182329616L;
/*#ManyToMany(cascade = {CascadeType.ALL},fetch=FetchType.EAGER,mappedBy = "userAddress",targetEntity=UserData.class)*/
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="user_id")
private UserData userdata;
#Id
#Column(name = "addr_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long addrid;
#Column(name = "dr_no")
#NotNull
private String doorNo;
#Column(name = "strt_name")
#NotNull
private String streetName;
#Column(name = "city")
#NotNull
private String city;
#Column(name = "country")
#NotNull
private String country;
/*#OneToOne(cascade=CascadeType.ALL)
#Column(name="user_id")*/
public UserData getUserdata() {
return userdata;
}
public void setUserdata(UserData userdata) {
this.userdata = userdata;
}
public Long getAddrid() {
return addrid;
}
public void setAddrid(Long addrid) {
this.addrid = addrid;
}
public String getDoorNo() {
return doorNo;
}
public void setDoorNo(String doorNo) {
this.doorNo = doorNo;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
UserData.java
package com.surya_spring.example.Model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.NonNull;
#Entity
#Table(name = "user_data")
public class UserData implements Serializable{
/**
* Serialization ID
*/
private static final long serialVersionUID = 8133309714576433031L;
/*#ManyToMany(targetEntity=UserAddress.class ,cascade= {CascadeType.ALL },fetch=FetchType.EAGER)
#JoinTable(name="userdata",joinColumns= #JoinColumn(name="userid"),inverseJoinColumns = #JoinColumn(name="userid"))
*/
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
#Column(name = "user_name")
#NonNull
private String userName;
#Column(name = "user_email")
#NonNull
private String userEmail;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
}
Repository:
package com.surya_spring.example.Repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.surya_spring.example.Model.UserData;
public interface UserDataRepository extends JpaRepository<UserData, Long>{
#Query(" FROM UserData where userId= :id")
public List<UserData> findBySearchTerm(#Param("id") Long id);
}
any one let me know the query to join this both the table to get city name from user_address where user_id=? joining user_data table
If you want to get the city for a user you can do:
#Query("SELECT ua.city FROM UserAddress ua WHERE ua.userdata.userId = ?1")
String findCityByUserId(Long userId);
Note that your entity names are used (like in your java classes) and not the table names in database! You do not have to do the join by yourself as you can use the properties of your domain models to access the related data
I have implemented shopping cart up to product. But have no idea on how to implement separate cart for each user.
Please share your ideas
Please share your effort / code along with your question always.
According to me this can go with many scenarios
One of the scenarios would be like,
User have One Cart, Cart will have many products and many Products belongs to many carts
Code goes as below, You can go ahead and add required parameters to the entity.
User Entity
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "USERS")
public class User {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "USER_NAME")
private String userName;
#OneToOne(mappedBy = "user", fetch = FetchType.LAZY)
private Cart cart;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
}
Cart Entity
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "CART")
public class Cart {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "CART_PRODUCT", joinColumns = #JoinColumn(name = "CART_ID") , inverseJoinColumns = #JoinColumn(name = "PRODUCT_ID") )
private Set<Product> products;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
Product Entity
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
#Entity
#Table(name = "PRODUCT")
public class Product {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String productName;
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "products")
private Set<Cart> carts;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Set<Cart> getCarts() {
return carts;
}
public void setCarts(Set<Cart> carts) {
this.carts = carts;
}
}
Hey i want to create a repository extending JpaRepository and fetch result without writing actual query,
In my example i have 2 tables Book and Author mapped by many to many relationship, suppose i want to fetch list of books by a particular author_id, since in my book entity, i don't have any field named author_id, so how will i use JPARepository to fetch results without writing actual query.
I was doing something like this: I created a bookDTO which contain object of Book and Author, and i created bookDTORepository extending JpaRepository and was calling List<Book> findByAuthor_Id(Integer id); , but its throwing error as: Not an managed type: class golive.data.bookdto My book class is
package golive.data;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sun.istack.internal.NotNull;
#Entity
#Table(name="book")
public class Book implements java.io.Serializable{
#Id
#GeneratedValue
private Integer id;
#NotNull
#Column(name="name")
private String name;
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
#JoinTable(name = "writes", joinColumns = { #JoinColumn(name = "book_id") }, inverseJoinColumns = { #JoinColumn(name = "author_id") })
private Set<Author> authors = new HashSet<Author>();
public Set<Author> getAuthors() {
return authors;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setAuthors(Set<Author> authors) {
this.authors = authors;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
My author class is
package golive.data;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sun.istack.internal.NotNull;
#Entity
#Table(name="author")
public class Author implements java.io.Serializable{
#Id
#GeneratedValue
#Column(name="id")
private Integer Id;
#NotNull
#Column(name="name")
private String name;
public Integer getId() {
return Id;
}
public String getName() {
return name;
}
public void setId(Integer id) {
Id = id;
}
public void setName(String name) {
this.name = name;
}
}
My bookdto class is
package golive.data;
public class bookdto {
private Book book;
private Author author;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
and my bookDTORepository is :
package golive.data;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface bookDTORepository extends JpaRepository<bookdto, Book> {
List<Book> findByAuthor_Id(Integer id);
}
My book controller method, i added:
#RequestMapping(value = "/listbyauthor", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<List<Book>> getBookByAuthorId(#RequestBody Author author,HttpServletResponse response) {
try {
Author temp = new Author();
temp.setId(author.getId());
temp.setName(author.getName());
return new ResponseEntity<>(bookRepository.findByAuthor(temp), HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
}
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
You want to find all books for a specific author so, given an Author, retrieve all Books whose set of Authors contains the specified Author.
The relevant JPQL operator is:
http://www.objectdb.com/java/jpa/query/jpql/collection#NOT_MEMBER_OF_
[NOT] MEMBER [OF] The [NOT] MEMBER OF operator checks if a specified
element is contained in a specified persistent collection field.
For example:
'English' MEMBER OF c.languages is TRUE if languages contains
'English' and FALSE if not. 'English' NOT MEMBER OF c.languages is
TRUE if languages does not contain 'English'.
As you may (or may not) be aware, you are using Spring Data which can derive some queries for you depending on method name. The docs do not however mention support for the [NOT] MEMBER [OF] operator:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
You will therefore need to add a custom query method to your repository which will look something like:
public interface BookRepository extends JpaRepository<Book, Integer> {
#Query("select b from Book b where ?1 MEMBER OF b.authors")
List<Book> findByAuthor(Author author);
}
and where the Author passed as a parameter is a persistent instance retrieved from the Database (via your AuthorRepository).