Spring JPA Query. Join Table with #OneToMany properties - sql

I have the following two Models:
class Game {
private long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Team> teams;
...
}
class Team {
private long id;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<User> members;
...
}
The user model holds a String username.
Now I want to create a query that results in the Team when I pass the Game and username as parameters:
public interface TeamRepository extends Repository<Team, Long> {
#Query("select t from Game g join Team t where g = :game and :username member of t.members")
Team findTeamByUserInGame(Game game, String username);
}
But I can't figure out how to join the Game table with the Team table and then how to check if username is in members. Any help?

In case of join, you can query for g.teams.members.username=:username
public interface TeamRepository extends Repository<Team, Long> {
#Query("select g from Game g where g = :game and g.teams.members.username=:username")
Team findTeamByUserInGame(Game game, String username);
}

The following works:
#Query(value = "SELECT t FROM Game g join g.teams t where g = :game and exists (select m from g.teams join t.members m where m = :user)")

Related

I need to retrieve a Rating class object. Joincolums values cannot be retrieve. How do I fix this?

I am trying to retrieve a Ratings class object. But userId and answer_id are foreign keys. Therefore they are join Columns.
#Query("SELECT r FROM Ratings r WHERE r.userId = ?1 AND r.answer_id = ?2")
public Ratings searchObject(Long userId,Long answerId);
public class Ratings {
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "userId")
private User user;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "answer_id")
private Answer answer;
//GETTERS AND SETTETRS
}
This error has occurred. when I tried to retrieve ratings object:
Caused by: org.hibernate.QueryException: could not resolve property:
userId of: com.smartedulanka.finalyearproject.datalayer.entity.Ratings
How do I fix this issue?
You need to decide if you want to use a HQL (recommended) or a native query:
HQL:
#Query("FROM Ratings r WHERE r.user.id = ?1 AND r.answer.id = ?2")
SQL:
#Query(nativeQuery=true, value="SELECT * FROM Ratings r WHERE r.userId = ?1 AND r.answer_id = ?2")

Select rows using mapping table with JPA

I do not know how to implement the query below in jpa, so please help.
select t.*
from team t
join team_memeber tm
on t.team_id = tm.team_id and tm.member_id = ?
The related entities are as follows.
public class Team {
#Id
int teamId;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "teamId")
Set<TeamMember> members = new HashSet<>();
}
public class TeamMember {
#Id
int id;
int teamId;
int memberId;
}

Nested query in JPQL

I have 2 entities -
#Table(name = "MM_MONITORING_CARD")
#Entity(name = "mm_MonitoringCard")
public class MonitoringCard extends StandardEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CLIENT_ID")
private Counterparty client;
#Column(name = "START_DATE")
private LocalDate startDate;
#Column(name = "END_DATE")
private LocalDate endDate;
...otherColumn
}
and
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
#Table(name = "MM_COUNTERPARTY")
#Entity(name = "mm_Counterparty")
#DiscriminatorValue("COUNTERPARTY")
#NamePattern("%s|name")
public class Counterparty extends StandardEntity {
#Column(name = "TYPE", insertable=false, updateable=false)
private String type;
...otherColumn
I need get all examples monitoringCard with condition - 1) between start date and end date 2) with Counterparty type = 'someType'
I do method -
List<MonitoringCard> monitoringCardList = dataManager.load(MonitoringCard.class)
.query("select distinct cm from mm_MonitoringCard m join mm_Counterparty cm where (m.current_date between cm.startDate and cm.endDate) and cm.type = :type")
.parameter("type", "someType")
.list();
but i get error, how can i make a correct request?
thanks
Your query is not correct. It should use a join like this:
select distinct m.Counterparty from mm_MonitoringCard m
where (m.current_date between m.Counterparty.startDate and m.Counterparty.endDate)
and m.Counterparty.type = :type
In JPA you don't need to do an explicit join when navigating on a ToOne relationship.

How to convert my native SQL query into a JPQL query

I'm trying to convert a native SQL query into a JPQL query. Presented first are the JPA entities and the repository interface:
LearnerActivity
#Entity
#Table(name = "learner_activity")
public class LearnerActivity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToMany
#JoinTable(name = "learner_activity_unit",
joinColumns = #JoinColumn(name="learner_activitys_id", referencedColumnName="ID"),
inverseJoinColumns = #JoinColumn(name="units_id", referencedColumnName="ID"))
private Set<Unit> units = new HashSet<>();
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "learner_activity_performance_criteria",
joinColumns = #JoinColumn(name="learner_activitys_id", referencedColumnName="ID"),
inverseJoinColumns = #JoinColumn(name="performance_criterias_id", referencedColumnName="ID"))
private Set<PerformanceCriteria> performanceCriterias = new HashSet<>();
}
LearnerJobOnSiteChecklistSectionItem
#Entity
#Table(name = "learner_job_on_site_checklist_section_item")
public class LearnerJobOnSiteChecklistSectionItem implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "learner_activity_id")
private LearnerActivity learnerActivity;
}
LearnerPortfolioPerformanceCriteriaAchievement
#Entity
#Table(name = "learner_portfolio_performance_criteria_achievement")
public class LearnerPortfolioPerformanceCriteriaAchievement implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "performance_criteria_id")
private PerformanceCriteria performanceCriteria;
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "learner_portfolio_performance_criteria_achievement_learner_job_on_site_checklist_section_item",
joinColumns = #JoinColumn(name="learner_portfolio_performance_criteria_achievements_id", referencedColumnName="ID"),
inverseJoinColumns = #JoinColumn(name="learner_job_on_site_checklist_section_items_id", referencedColumnName="ID"))
private Set<LearnerJobOnSiteChecklistSectionItem> learnerJobOnSiteChecklistSectionItems = new HashSet<>();
}
I'm looking to get all LearnerPortfolioPerformanceCriteriaAchievements which have the same PerformanceCriteria as a given LearnerJobOnSiteChecklistSectionItem's Activity.
LearnerPortfolioPerformanceCriteriaAchievementRepository
public interface LearnerPortfolioPerformanceCriteriaAchievementRepository extends JpaRepository<LearnerPortfolioPerformanceCriteriaAchievement,Long> {
#Query("select distinct lppca from LearnerJobOnSiteChecklistSectionItem si inner join si.learnerActivity la inner join LearnerPortfolioPerformanceCriteriaAchievement lppca where lppca.performanceCriteria member of la.performanceCriterias and si.id =:sectionItemId")
public List<LearnerPortfolioPerformanceCriteriaAchievement> findForSectionItem(#Param("sectionItemId") Long sectionItemId);
}
Native SQL
SELECT
a.id
FROM
learner_job_on_site_checklist_section_item AS i
JOIN
learner_activity_performance_criteria AS c
ON
c.learned_activitys_id = i.learned_activitys_id
INNER JOIN
learner_portfolio_performance_criteria_achievement AS a
ON
a.performance_criteria_id = c.performance_criterias_id
where i.id = 2
Understanding that I can replace my SQL ON with WHERE clauses, my best JPQL attempt so far is this:
SELECT
DISTINCT lppca
FROM
LearnerJobOnSiteChecklistSectionItem si
INNER JOIN
si.learnerActivity la
INNER JOIN
LearnerPortfolioPerformanceCriteriaAchievement lppca
WHERE
lppca.performanceCriteria MEMBER OF la.performanceCriterias
AND si.id =:sectionItemId
However, running this JPQL throws the following exception:
Caused by: java.lang.IllegalStateException: No data type for node: org.hibernate.hql.internal.ast.tree.IdentNode
\-[IDENT] IdentNode: 'lppca' {originalText=lppca}
The following query will work:
SELECT
a
FROM
LearnerPortfolioPerformanceCriteriaAchievement a
, LearnerActivity v
, LearnerJobOnSiteChecklistSectionItem i
WHERE
i.id = :sectionItemId
AND i.learnerActivity = v
AND a.performanceCriteria MEMBER OF v.performanceCriterias
AND i MEMBER OF a.learnerJobOnSiteChecklistSectionItems
Have created a sample application to test the query (I have used shorter and simpler class names to make it easy to read).

java.lang.IllegalArgumentException with toplink and JPA

I've a problem with JPA, whenever execute this query
#NamedQuery(name = "Usuario.getUsuarioIntento", query = "SELECT u.intentos_id FROM Usuario u WHERE u.username = :username and u.borrado = 0")
i get this error:
java.lang.IllegalArgumentException: NamedQuery of name: Usuario.getUsuarioIntento not found.
But if i execute this query
#NamedQuery(name = "Usuario.getUsuarioIntento", query = "SELECT u.id FROM Usuario u WHERE u.username = :username and u.borrado = 0")
Work fine,Why?
My table,Usuario:
MY USER TABLE
i try with other column as 'superusuario','version_jpa' and doesn't work, the only columns that work fine are 'id,'borrado' and 'username'
Class Usuario:
#Temporal(TemporalType.TIMESTAMP)
private Date fechaCreacion;
#Id
#GeneratedValue (strategy=GenerationType.AUTO)
private int id;
#OneToOne(cascade = CascadeType.ALL)
private Password password;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY)
private List<Password> clavesAntiguas;
#OneToOne
private Persona persona;
private String sessionId;
private String username;
#ManyToOne(cascade = CascadeType.REFRESH)
private Rol rol;
#ManyToOne(cascade = CascadeType.REFRESH)
private Perfil perfil;
#OneToOne (cascade = CascadeType.ALL)
private IntentosBloqueo intentos;
private boolean superUsuario;
private int borrado;
private int esManager;
#OneToMany ( cascade = {CascadeType.ALL} , fetch = FetchType.LAZY)
private Collection<UsuarioSociedad> sociedades;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
#JoinTable (name="USR_UND_VIS",
joinColumns={
#JoinColumn (name="ID_USU", table="USUARIO", referencedColumnName="ID"),
},
inverseJoinColumns=
#JoinColumn (name="ID_UNI", table="UND_ORG", referencedColumnName="ID")
)
private List<UnidadOrganizativa> unidadesVisibles;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
#JoinTable (name="USR_UND_DIS",
joinColumns={
#JoinColumn (name="ID_USU", table="USUARIO", referencedColumnName="ID"),
},
inverseJoinColumns=
#JoinColumn (name="ID_UNI", table="UND_ORG", referencedColumnName="ID")
)
private List<UnidadOrganizativa> unidadesDisponibles;
Because Named query works on Entity objetc not on datbase column. You try to find another entity object which contains that id. In That case your named query will give you the object of that entity class and from that object u can get the id or whtever fiels of that entity.
JPA named query is not like SQL or oracle query.
Iin in DB your column name is xyz but in entity your column name is ABC then you have to fetch ABC in named query not XYZ.