JPA : Implicit find by composite primary key - sql

Please I'm trying to find Quiz by Audit (using spring data jpa) and there must be an implicit search for the quizSubCategory which has a composite key, here are the classes :
Quiz entity:
#Entity
#Table(name = "quiz")
public class Quiz {
#EmbeddedId
private QuizCK id;
#Column
private String title;
#Column
private String status;
#Column
private String state;
#Column(name = "start_date")
private Date startDate;
#Column(name = "end_date")
private Date endDate;
#Column
private String reference;
#Column
private String results;
#Column(name = "is_default")
private boolean isDefault;
#ManyToOne
#JoinColumn(name = "id_audit")
private Audit audit;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "id_quiz_sub_category", insertable = false, updatable = false),
#JoinColumn(name = "id_language", insertable = false, updatable = false)
})
private QuizSubCategory quizSubCategory;
#MapsId("idLanguage")
#ManyToOne
#JoinColumn(name="id_language", insertable = false, updatable = false)
private Language language;
public Quiz() {
}
// constructor & getters & setters
}
QuizSubCategory entity:
Entity
#Table(name = "quiz_sub_category")
public class QuizSubCategory implements Serializable {
#EmbeddedId
private QuizSubCategoryCK id;
private String libelle;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "id_quiz_category", insertable = false, updatable = false),
#JoinColumn(name = "id_language", insertable = false, updatable = false)
})
private QuizCategory quizCategory;
#MapsId("idLanguage")
#ManyToOne
#JoinColumn(name="id_language", insertable = false, updatable = false)
private Language language;
public QuizSubCategory() {
super();
}
//constructor & getters & setters
}
QuizSubCategoryCK (primary key):
#Embeddable
public class QuizSubCategoryCK implements Serializable {
#Column(name = "id_quiz_sub_category", insertable = false, updatable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private int idQuizSubCategory;
#Column(name = "id_language", insertable = false, updatable = false)
private int idLanguage;
public QuizSubCategoryCK() {
}
public int getIdQuizSubCategory() {
return idQuizSubCategory;
}
public void setIdQuizSubCategory(int idQuizSubCategory) {
this.idQuizSubCategory = idQuizSubCategory;
}
public int getIdLanguage() {
return idLanguage;
}
public void setIdLanguage(int idLanguage) {
this.idLanguage = idLanguage;
}
}
QuizRepository :
public interface QuizRepository extends JpaRepository<Quiz,QuizCK> {
List<Quiz> findByAuditAndLanguage(Audit audit, Language language);
}
Controller:
#RequestMapping(value = "/quizzes/{auditId}", method = RequestMethod.GET)
public List<QuizBean> listQuizzes(#PathVariable int auditId){
AuditBean auditBean = auditService.getAudit(auditId);
LanguageBean languageBean = languageService.getLanguageById(1);
List<QuizBean> quizzes = quizService.findByAudit(AuditMapper.fromBean(auditBean),LanguageMapper.fromBean(languageBean));
return quizzes;
}
I'm getting the following error :
Unable to find jpa.entity.QuizSubCategory with id jpa.entity.QuizSubCategoryCK#79a59c48; nested exception is javax.persistence.EntityNotFoundException: Unable to find jpa.entity.QuizSubCategory with id jpa.entity.QuizSubCategoryCK#79a59c48
Any hints please ?!

Related

How to make JPA JOIN query list giving only one item instead of all items by condition

I have some Entities looks like this. Very abstract:
#Entity
class Man {
#Id
String name;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "name", cascade = CascadeType.ALL)
List<Car> carList;
}
#IdClass(TypeId.class)
#Entity
class Car {
#Id
#NonNull
String name;
#Id
#NonNull
String class;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "class",
referencedColumnName = "class",
insertable = false,
updatable = false)
Engine engine;
}
#Entity
class Engine() {
#Id
#NonNull
String class;
String type;
Integer count;
}
class TypeId {
String name;
String class;
}
I need to construct #Query - select MAN with condition: if Engine types are equals, I need to take one Car with less Engine count. And return Man with only one Car if condition is met. Otherwise return Man with all cars.

Making SQL/JPQL query to select all topics that matches both keywords

Challenge:
I want to create a query that selects Topics that match both the keyword ID´s "Java" and "sql", the Topic with ID = 1 matches both keywords "Java" and "Sql.
I have implemented two simple entities Topic and Keyword. They have a bidirectional ManyToMany relationship:
#Entity
#Table(name = "Topic")
public class Topic implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "topicID")
private Long id;
#Column(name = "topicTitle")
private String title = "";
#ManyToMany
#JoinTable(name = "Join_Topic_Keyword",
joinColumns = #JoinColumn(name = "Topic_ID"),
inverseJoinColumns = #JoinColumn(name = "Keyword_ID"))
private Set<Keyword> keywords;
}
#Entity
#Table(name = "Keyword")
public class Keyword implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "keywordID")
private String id;
#ManyToMany(mappedBy = "keywords")
private Set<Topic> topics;
}
Here is the structure table.
And This is the result from Join_Topic_Keyword

How convert this SQL query into JPA criteriaBuilder query?

I have the following Data Base diagram:
And I have the following quite simple SQL query:
SELECT Subject.id, Subject.name, subSelect.count
FROM
(SELECT Subject.id AS id, COUNT(*) AS count
FROM Question
JOIN Subject_Question ON Subject_Question.question_id = Question.id
JOIN Subject ON Subject.id = Subject_Question.subject_id
WHERE Subject.state = 0 AND Question.state = 0
GROUP BY Subject.id) AS subSelect
JOIN Subject ON Subject.id = subSelect.id
My task is to present this query Java application in term of criteriaBuilder from JPA.
This is my domain classes in Java application:
#Entity
#Table(name = "Question")
public class Question {
Long id;
String text;
ActiveUser activeUser;
Long dateCreation;
Long dateStateSetting;
EntityState state;
Set<Subject> subjects;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "text", length = 5000, nullable = false)
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#ManyToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "activeUser", nullable = false)
public ActiveUser getActiveUser() {
return activeUser;
}
public void setActiveUser(ActiveUser activeUser) {
this.activeUser = activeUser;
}
#Column(name = "dateCreation")
public Long getDateCreation() {
return dateCreation;
}
public void setDateCreation(Long dateCreation) {
this.dateCreation = dateCreation;
}
#Column(name = "dateStateSetting")
public Long getDateStateSetting() {
return dateStateSetting;
}
public void setDateStateSetting(Long dateStateSetting) {
this.dateStateSetting = dateStateSetting;
}
#Enumerated(EnumType.ORDINAL)
#Column(name = "state", nullable = false)
public EntityState getState() {
return state;
}
public void setState(EntityState state) {
this.state = state;
}
#ManyToMany(mappedBy = "questions")
public Set<Subject> getSubjects() {
return subjects;
}
public void setSubjects(Set<Subject> subjects) {
this.subjects = subjects;
}
}
And
#Entity
#Table(name = "Subject")
public class Subject {
Long id;
String name;
EntityState state;
Long dateCreation;
Boolean ifGroup;
List<Question> questions;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Enumerated(EnumType.ORDINAL)
#Column(name = "state", nullable = false)
public EntityState getState() {
return state;
}
public void setState(EntityState state) {
this.state = state;
}
#Column(name = "dateCreation")
public Long getDateCreation() {
return dateCreation;
}
public void setDateCreation(Long dateCreation) {
this.dateCreation = dateCreation;
}
#Column(name = "ifGroup", nullable = false)
public Boolean getIfGroup() {
return ifGroup;
}
public void setIfGroup(Boolean ifGroup) {
this.ifGroup = ifGroup;
}
#ManyToMany(cascade = CascadeType.REMOVE)
#JoinTable(
name = "Subject_Question",
joinColumns = #JoinColumn(name = "subject_id"),
inverseJoinColumns = #JoinColumn(name = "question_id")
)
public List<Question> getQuestions() {
return questions;
}
public void setQuestions(List<Question> questions) {
this.questions = questions;
}
}
I start with the following:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Question> criteria = criteriaBuilder.createQuery(Question.class);
Root<Question> i = criteria.from(Question.class);
criteria.multiselect(
i.get("id"),
criteriaBuilder.count(i)).
But at this point I ran into a problem - I must to join with Subject_Question but I don't have class for it in Java application.
So is it possible to represent this SQL query in term of criteriaBuilder from JPA?

#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.

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?