Spring Data -- Query JOIN Validation ERROR -- Validation failed for query for method - sql

I'm trying to do a 3 table Join Query with Spring data and I'm running into a query validation issue.
The exact error I get is:
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.somethinng.domain.subscriberCategoriesRepository.findByJoin()!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:92)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:62)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:72)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:53)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:144)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:212)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:436)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:221)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:277)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:263)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:101)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 39 more
On the Database side here are my three tables
create table subscribers(
id int auto_increment primary key,
email varchar(255),
unique (email));
create table categories (
id int auto_increment primary key,
source varchar(255) not null,
description varchar(255) not null);
create table subscriberCategories(
subscriber int not null,
source int not null,
primary key (subscriber,source), -- prevents dupes
constraint `fk_2user` foreign key (subscriber) references subscribers(id));
And here are my POJO's and Repositories
Subscribers
#Entity
#Getter
#Setter
public class Subscribers {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotNull
private String email;
public Subscribers() { }
public Subscribers(Integer id) {
this.id = id;
}
public Subscribers(String email, String description) {
this.email = email;
}
}
Categories
#Entity
#Getter
#Setter
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotNull
private String description;
#NotNull
private String source;
public Categories() { }
public Categories(Integer id) {
this.id = id;
}
public Categories(String source, String description) {
this.source = source;
this.description = description;
}
}
SubscriberCategories
#Entity
#Getter
#Setter
public class subscriberCategories {
#Id
#Column(name = "subscriber")
private Integer id;
#NotNull
private Integer source;
public subscriberCategories() {
}
public subscriberCategories(Integer subscriberId) {
this.id = subscriberId;
}
public subscriberCategories(Integer source, Integer subscriberId) {
this.source = source;
this.id = subscriberId;
}
}
Repositories
SubscriberRepository
#Repository
public interface SubscriberRepository extends CrudRepository<Subscribers, Integer> {
}
CategoriesRepository
#Repository
public interface CategoriesRepository extends CrudRepository<Categories, Integer> {
List<Categories> findById(Integer id);
Long deleteBySource(String source);
List<Categories> findBySource(String source);
}
subscriberCategoriesRepository
#Transactional
#Repository
public interface subscriberCategoriesRepository extends CrudRepository<subscriberCategories, Integer> {
#Query(value = "SELECT DISTINCT s.email as Subscriber, c.source as Source from Subscribers s" +
"Inner Join subscriberCategories sc on s.id = sc.subscriber" +
"Inner Join Categories c on sc.subscriber = s.id where s.email = 'xxxxx#gmail.com'")
List<subscriberCategories> findByJoin();
Lastly I have the following unit test which is throwing the error when I run it
#RunWith(SpringRunner.class)
#SpringBootTest
#EnableJpaRepositories(basePackageClasses = subscriberCategories.class)
#Transactional
public class subscriberCategoriesTest {
#Autowired
subscriberCategoriesRepository subscriberCategoriesRepository;
#Test
public void testLoadCategories() {
List<subscriberCategories> subscriberCategories = (List<subscriberCategories>) subscriberCategoriesRepository.findByJoin();
assertEquals("Should contain something", 1, subscriberCategories.size());
}
If someone give me a hand with this I would really appreciate it
Thanks

Related

I have problem with joining two entity classes

I wrote two controller class in spring application called player and team and I want join this model classes for connect sql database and I write code but it give me error so please help me to resolve that I'm sure problem happen in below two files and my other dependencies and database connection working well
my Team class
package com.withAngular.team;
import java.util.ArrayList;
import java.util.List;
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.Table;
import org.springframework.beans.factory.annotation.Autowired;
import com.withAngular.demo.player.Player;
#Entity
#Table(name = "team")
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "team")
private String team;
#Column(name = "description")
private String description;
#Column(name = "owner")
private String owner;
#Column(name = "total_played")
private int totalPlayed;
#Column(name = "total_won")
private int totalWon;
#Column(name = "total_lost")
private int totalLost;
#Column(name = "no_result")
private int noResult;
#OneToMany
(mappedBy = "team", cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private List<Player> players = new ArrayList<>();
public Team(int id, String name, String description, String owner, int totalplayed, int totalwon, int totallost, int noresult) {
this.setId(id);
this.setDescription(description);
this.setOwner(owner);
this.setTotalPlayed(totalplayed);
this.setTotalWon(totalwon);
this.setTotalLost(totallost);
this.setNoResult(noresult);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTeam() {
return team;
}
public void setTeam(String team) {
this.team = team;
}
public List<Player> getPlayers() {
return players;
}
public void setPlayers(List<Player> players) {
this.players = players;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public int getTotalPlayed() {
return totalPlayed;
}
public void setTotalPlayed(int totalPlayed) {
this.totalPlayed = totalPlayed;
}
public int getTotalWon() {
return totalWon;
}
public void setTotalWon(int totalWon) {
this.totalWon = totalWon;
}
public int getTotalLost() {
return totalLost;
}
public void setTotalLost(int totalLost) {
this.totalLost = totalLost;
}
public int getNoResult() {
return noResult;
}
public void setNoResult(int noResult) {
this.noResult = noResult;
}
}
my Player class
package com.withAngular.demo.player;
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 com.withAngular.team.Team;
#Entity
// #Table(name=PLAYER) when table name different from the class name
public class Player {
#Id // primary key
#GeneratedValue(strategy = GenerationType.AUTO) // auto increment
private int id;
// #Column(name = "PlayerName") when db table column name different from the
// property name assigned below
private String playerName;
private String preference;
#Column(name= "match_played")
private int matchPlayed;
private int runs;
private int wickets;
#Column(name= "highest_score")
private int highestScore;
#Column(name="best_wicket")
private String bestWicket;
private int fifties;
private int centuries;
private int thirties;
private int catches;
private int stumpings;
private int fours;
private int sixes;
#Column(name = "strike_rate")
private double strikeRate;
private double average;
#ManyToOne(targetEntity = Team.class)
#JoinColumn(name= "team_id")
private Team team;
// getters and setters
public Player(int id, String playername, String preference, int matchplayed, int runs, int wickets, int highestscore, String bestWicket, int fifties, int centuries, int thirties, int caches, int stumpings,int fours, int sixes, double strikerate, double average) {
// TODO Auto-generated constructor stub
this.setId(id);
this.setPlayerName(playername);
this.setPreference(preference);
this.setMatchPlayed(matchplayed);
this.setRuns(runs);
this.setWickets(wickets);
this.setHighestScore(highestscore);
this.setBestWicket(bestWicket);
this.setFifties(fifties);
this.setCenturies(centuries);
this.setThirties(thirties);
this.setCatches(caches);
this.setStumpings(stumpings);
this.setFours(fours);
this.setSixes(sixes);
this.setStrikeRate(strikerate);
this.setAverage(average);
}
public int getId() {
return id;
}
public String getPreference() {
return preference;
}
public void setPreference(String preference) {
this.preference = preference;
}
public int getMatchPlayed() {
return matchPlayed;
}
public void setMatchPlayed(int matchPlayed) {
this.matchPlayed = matchPlayed;
}
public int getRuns() {
return runs;
}
public void setRuns(int runs) {
this.runs = runs;
}
public int getWickets() {
return wickets;
}
public void setWickets(int wickets) {
this.wickets = wickets;
}
public int getHighestScore() {
return highestScore;
}
public void setHighestScore(int highestScore) {
this.highestScore = highestScore;
}
public String getBestWicket() {
return bestWicket;
}
public void setBestWicket(String bestWicket) {
this.bestWicket = bestWicket;
}
public int getFifties() {
return fifties;
}
public void setFifties(int fifties) {
this.fifties = fifties;
}
public int getCenturies() {
return centuries;
}
public void setCenturies(int centuries) {
this.centuries = centuries;
}
public int getThirties() {
return thirties;
}
public void setThirties(int thirties) {
this.thirties = thirties;
}
public int getCatches() {
return catches;
}
public void setCatches(int catches) {
this.catches = catches;
}
public int getStumpings() {
return stumpings;
}
public void setStumpings(int stumpings) {
this.stumpings = stumpings;
}
public int getFours() {
return fours;
}
public void setFours(int fours) {
this.fours = fours;
}
public int getSixes() {
return sixes;
}
public void setSixes(int sixes) {
this.sixes = sixes;
}
public double getStrikeRate() {
return strikeRate;
}
public void setStrikeRate(double strikeRate) {
this.strikeRate = strikeRate;
}
public double getAverage() {
return average;
}
public void setAverage(double average) {
this.average = average;
}
public Team getTeam() {
return team;
}
public void setTeam(Team team) {
this.team = team;
}
public void setId(int id) {
this.id = id;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
}
and after run as spring boot app it give me below error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: #OneToOne or #ManyToOne on com.withAngular.demo.player.Player.team references an unknown entity: com.withAngular.team.Team
It is a very simple problem, You need to put both the entity classes in same package and that package should be either the package which holds the main application class that is annotated with
#SpringBootApplication
Or any of the sub package of parent package.
Eg: If package of your parent class is com.withAngular than put the Team and Player class also in the same package.
Change package com.withAngular.team; to package com.withAngular; in Team class.
Change package com.withAngular.demo.player; to package com.withAngular; in Player class.
Use the Annotation EnableJpaRepositories in your class annotated with #SpringBootApplication and set the
attribute basePackages to a common package.
So in your case com.withAngular.
#EnableJpaRepositories(basePackages="com.withAngular")
But it is better to moven entities in the same subpackage not in the "root" package of your application

JPA OneToMany bidirectional relation [EclipseLink-63] error

Please can you help me? In JPA, I try to create a OneToMany bidirectional relation, but I have the following errors :
"[EclipseLink-63] : The instance creation method [entity.OrderLine.], with no parameters, does not exist, or is not accessible.
[EclipseLink-28019] : Deployment of PersistenceUnit [simple-jpaPU] failed. Close all factories for this PersistenceUnit."
There are my entities :
OneToMany Entity :
package entity;
import java.util.*;
import java.io.Serializable;
import javax.persistence.*;
import org.eclipse.persistence.annotations.TimeOfDay;
#Entity
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
#OneToMany(mappedBy = "o")
private List<OrderLine> orderLines;
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public List<OrderLine> getOrderLines() {
return orderLines;
}
public void setOrderLines(ArrayList<OrderLine> orderLines) {
this.orderLines = orderLines;
}
public Order(Date creationDate) {
this.creationDate = creationDate;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public String toString() {
return "entity.Order[ id=" + id + " ]";
}
}
ManyToOne Entity :
package entity;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#Table(name="orderline_table")
public class OrderLine implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String item;
private Double unitPrice;
private Integer quantity;
#ManyToOne
Order o;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public Double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(Double unitPrice) {
this.unitPrice = unitPrice;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public OrderLine(String item, Double unitPrice, Integer quantity) {
this.item = item;
this.unitPrice = unitPrice;
this.quantity = quantity;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public String toString() {
return "entity.OrderLine[ id=" + id + " ]";
}
}
It fails because OrderLine does not have no-arg constructor. It is required as stated in JPA 2.1 specification (Chapter 2.1):
The entity class must have a no-arg constructor. The entity class may have other constructors as well.The no-arg constructor must be public or protected.
Default constructor is not generated because other constructor is given. Problem can be fixed by adding following constructor:
public OrderLine() {
}

#Query Spring Data JPA Update Not Working

Here is my User entity:
#Entity
#Table(name="users")
public class User implements IBaseEntity<User> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long userId;
#Column(unique = true)
#NotNull
private String username;
#Column(unique = true)
#NotNull
private String email;
#Column
#NotNull
private String password;
// #formatter:off
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "users_roles",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "role_id") })
// #formatter:on
private List<Role> roles = new ArrayList<Role>();
#Column
#NotNull
private Boolean locked;
...
}
Here is my Role entity:
#Entity
#Table(name="roles")
public class Role implements IBaseEntity<Role> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long roleId;
#Column(unique = true)
#NotNull
private String name;
...
}
Here is my User service:
package org.quickloanconnect.service;
public interface IUsersService extends IBaseService<User>{
public void updateUserRolesById(List<Role> roles, Long userId);
...
}
Here is the UserServiceImpl :
#Service
#Transactional
public class UsersServiceImpl extends AbstractServiceImpl<User> implements
IUsersService {
...
#Override
#Transactional
public void updateUserRolesById(List<Role> roles, Long user_id) {
userDao.updateUserRolesById(roles, user_id);
}
...
}
And here is the dao:
public interface IUsersDao {
...
#Modifying
#Query("UPDATE User u SET u.roles = :roles WHERE u.userId = :userId")
public void updateUserRolesById(#Param("roles") List<Role> roles,
#Param("userId") Long userId);
...
}
When I run this update, I get the following: SqlExceptionHelper : No value specified for parameter 2 . What is causing this? When I update my user with a single role, I see that a List of size one is getting to the dao with the correct userId (both parameters present), but the update seems to fail at the dao level with the "SqlExceptionHelper : No value specified for parameter 2" error message.

Error reading annotations with composite key in EBean

Following this link
I would like to use OneToMany instead ManyToMany annotation, having middle class with composite key in it using Ebean. I have this error:
java.lang.RuntimeException: Error reading annotations for models.SoftwareTagPk
This is my SoftwareTagPk class:
#Embeddable
public class SoftwareTagPk implements Serializable {
#ManyToOne
private Tag tag;
#ManyToOne
private Software software;
...
}
And SoftwareTag class:
#Entity
public class SoftwareTag extends Model {
#EmbeddedId
private SoftwareTagPk pk = new SoftwareTagPk();
#Transient
public Tag getTag() {
return pk.getTag();
}
public void setTag(Tag aTag) {
pk.setTag(aTag);
}
#Transient
public Software getSoftware() {
return pk.getSoftware();
}
public void setSoftware(Software aSoftware) {
pk.setSoftware(aSoftware);
}
}
Also in logs:
Error with association to [class models.Tag] from
[models.SoftwareTagPk.tag]. Is class models.Tag registered?
How to fix it?
To make this code work you have to do:
In your SoftwareTagPk class put only id's of Tag and Software
Move #ManyToOne relations to SoftwareTag class
Add #JoinColumn annotations with attributes updatable and insertable set to false.
Override setters setTag and setSoftware in SoftwareTag class. In these setters you will rewrite id's to composite key.
Main idea of this solution is that SoftwareTag has composite key and #ManyToOne relations and they are mapped to the same collumns.
This is the code:
Tag.java
#Entity
public class Tag extends Model {
#Id
private Integer id;
#OneToMany(mappedBy="tag")
public List<SoftwareTag> softwareTags;
public Integer getId() {
return id;
}
public void setId(Integer aId) {
id=aId;
}
public static Finder<Integer,Tag> find = new Finder<Integer,Tag>(
Integer.class, Tag.class
);
}
Software.java
#Entity
public class Software extends Model {
#Id
private Integer id;
#OneToMany(mappedBy="software")
public List<SoftwareTag> softwareTags;
public Integer getId() {
return id;
}
public void setId(Integer aId) {
id=aId;
}
}
SoftwareTag.java
#Entity
public class SoftwareTag extends Model {
SoftwareTag() {
pk = new SoftwareTagPk();
}
#EmbeddedId
private SoftwareTagPk pk = new SoftwareTagPk();
#ManyToOne
#JoinColumn(name = "tag_id", insertable = false, updatable = false)
private Tag tag;
#ManyToOne
#JoinColumn(name = "software_id", insertable = false, updatable = false)
private Software software;
public Tag getTag() {
return tag;
}
public void setTag(Tag aTag) {
tag = aTag;
pk.tag_id = aTag.getId();
}
public Software getSoftware() {
return software;
}
public void setSoftware(Software aSoftware) {
software = aSoftware;
pk.software_id = aSoftware.getId();
}
}
SoftwareTagPk.java
#Embeddable
public class SoftwareTagPk implements Serializable {
public Integer tag_id;
public Integer software_id;
#Override
public int hashCode() {
return tag_id + software_id;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
SoftwareTagPk pk = (SoftwareTagPk)obj;
if(pk == null)
return false;
if (pk.tag_id.equals(tag_id) && pk.software_id.equals(software_id)) {
return true;
}
return false;
}
}

Hibernate : #OneToMany : Always deleting and reinserting the child records

Please help me resolve this issue. I tried googling for a solution and couldn't find one for this.
Table structure
Table: Catalog
catalog_id (primary key)
name
Table: Catalog_Locale
catalog_id
locale_id
sequence
composite key(catalog_id,locale_id)
Class
public Class Catalog{
#Id
#Column(name = "CATALOG_ID", nullable = false)
private String catalogId;
#Column(name = "NAME")
private String name;
#OneToMany(targetEntity = CatalogLocale.class,fetch=FetchType.LAZY)
#JoinColumn(name = "CHILD_CATALOG_ID", nullable = false)
#Cascade(value = {})
protected List<CatalogLocale> locales = new ArrayList<CatalogLocale>(10);
public void setCatalogId( String catalogId ){
this.catalogId = catalogId;
}
public void setName( String name ){
this.name = name;
}
public void setLocales( List<CatalogLocale> locales ){
this.locales = locales;
}
public void getCatalogId(){
return catalogId;
}
public void getName(){
return name;
}
public void getLocales(){
return locales;
}
}
public class CatalogLocale{
#EmbeddedId
CatalogLocalePk catalogLocalePk;
#Column(name = "SEQUENCE")
private int sequence;
public void setCatalogLocalePk( CatalogLocalePk catalogLocalePk ){
this.catalogLocalePk = catalogLocalePk;
}
public void setSequence( int sequence ){
this.sequence = sequence;
}
public CatalogLocalePk getCatalogLocalePk(){
return catalogLocalePk;
}
public int getSequence(){
return sequence;
}
#Embeddable
public static class CatalogLocalePk{
#Column(name = "CATALOG_ID", nullable = false)
private String catalogId;
#Column(name = "LOCALE_ID", nullable = false)
private String localeId;
public CatalogLocalePk(){
}
public CatalogLocalePk( String catalogId, String localeId ){
this.catalogId = catalogId;
this.localeId = localeId;
}
public void setCatalogId( String catalogId ){
this.catalogId = catalogId;
}
public void setLocaleId( String localeId ){
this.localeId = localeId;
}
public String getCatalogId(){
return catalogId;
}
public String getLocaleId(){
return localeId;
}
}
}
The code works for fine for the insert operation, but for any update to the Catalog will trigger for delete and reinsert all entries of the child table.
Is there any solution for this?