JPQL - How can I get an extra param inside my entity? - java

I am new to JPQL and I am trying to get an extra parameter that is not in the entity, but I am not finding how to do it.
Through searched here in the forum I found out that some uses a DTO for it, but I am not knowing how to apply that.
Here is my entity:
#Entity
#Table(name = "person")
public class Person implements Serializable {
private int id;
private String name;
private String email;
private int age;
...
}
And my JPQL:
SELECT COUNT(a.name) as countOfNames, a FROM Person a WHERE a.name like :name
How can I get the countOfNames result inside of myentity object since it is not a column?

The simplest way is to use a constructor expression
package com.entites
public class PersonDto {
private Person person;
private Integer countOfNames;
public PersonDto(Person person, Integer countOfNames) {
this.person = person;
this.countOfNames = countOfNames;
}
}
select new com.entites.PesronDto(a, count(a.name))
from Person a
where a.name like :name

Related

Subsequent query execution in JPA

Let's assume there is a class named Person with following structure in spring boot
#Entity
class Person {
Long id;
String name;
#OneToMany
Set<PhoneNumber> phoneNumbers;
}
Person consists of set of phone numbers.
#Entity
class PhoneNumber {
Long id;
#ManyToOne
#JoinByColumn("person_id")
Person person;
String category;
String mobileNumber;
String phoneNumber;
}
PhoneNumber is a class which consists of above fields where category represents mobile or phone etc.
class PersonRepository extends JPARepository<Person, Long> {
Person findById(Long id);
}
So, whenever I want to fetch Person details with some id, I will call the above method findById , then it should fetch Person details along with phoneNumbers whose category is mobile.
The approach should be whenever it executes query internally for the findById method, it should execute subsequent query for fetching PhoneNumber whose category is mobile.
Is there any way I can get it as mentioned above or is there any other approach for achieving it? Please let me know.
PS: If there are any issues or errors in my way of asking please comment below. It will help me.
You can get it. Refer this:
Repo:
class PersonRepository extends JPARepository<Person, Long>,JpaSpecificationExecutor<Post> {
Person findById(Long id);
}
public static Specification<Person> search(Long id) {
return ((root, criteriaQuery, criteriaBuilder) -> {
criteriaQuery.distinct(true);
return criteriaBuilder.and(
criteriaBuilder.equal(root.get("id"), id),
criteriaBuilder.equal(root.join("phone_number").get("category"), "mobile")
);
});
}
personRepo.findAll(search(10));
You can try this method-
// method in Person entity class
public static List<Person> findByIdMobile(long id, String category) {
return find("id = ?1 and phoneNumbers.category = ?2", id, category).list();
}
// can use this as
List<Person> mobilePersons = Person.findByIdMobile(1234,"mobile");

How to search with JpaRepository and nested list of objects?

Description
There is a PersonRepository and Person entity,
Person class contains List<Qualification>. Qualification class has 3 simple fields.
I have tried to add #Query annotation on custom method and use JPQL to get the results, but Qualification class fields were not available for manipulation in JPQL as it repository itself contains List<Qualification> instead of just a simple field of Qualification.
How can I search by these Qualification's nested fields?
Query
Now I need to find list of person entity where qualification's experienceInMonths is greater than 3 and less than 9 AND qualification's name field = 'java'.
Code
Person.java
#Data
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
#NotEmpty
#Size(min = 2)
private String name;
#NotEmpty
#Size(min = 2)
private String surname;
#ElementCollection(targetClass = java.util.ArrayList.class, fetch = FetchType.EAGER)
private List<Qualification> qualifications = new ArrayList<>();
}
PersonRepository.java
#Repository
public interface PersonRepository extends JpaRepository<Person, String> {
}
Qualification.java
#Data
#AllArgsConstructor
public class Qualification implements Serializable {
#Id #GeneratedValue
private String id;
private String name;
private String experienceInMonths;
}
EDIT: not duplicate of this post, as here is the collection of nested objects. Not just single reference.
First, change experienceInMonths from String to int (otherwise you can not compare the string with the number). Then you can try to use this 'sausage':
List<Person> findByQualifications_experienceInMonthsGreaterThanAndQualifications_experienceInMonthsLessThanAndName(int experienceGreater, int experienceLess, String name);
Or you can try to use this pretty nice method:
#Query("select p from Person p left join p.qualifications q where q.experienceInMonths > ?1 and q.experienceInMonths < ?2 and q.name = ?3")
List<Person> findByQualification(int experienceGreater, int experienceLess, String name);
W can use ‘_’ (Underscore) character inside the method name to define where JPA should try to split.
In this case our method name will be
List<Person> findByQualification_name(String name);

Spring Data Projection with OneToMany returns too many results

I have a JPA entity (Person) with onetomany relation (ContactInfo).
#Entity
public class Person {
#Id
#GeneratedValue
private Integer id;
private String name;
private String lastname;
private String sshKey;
#OneToMany(mappedBy = "personId")
private List<ContactInfo> contactInfoList;
}
#Entity
public class ContactInfo {
#Id
#GeneratedValue
private Integer id;
private Integer personId;
private String description;
}
I've defined a projection interface that includes this onetomany relation as described here.
public interface PersonProjection {
Integer getId();
String getName();
String getLastname();
List<ContactInfo> getContactInfoList();
}
public interface PersonRepository extends JpaRepository<Person,Integer> {
List<PersonProjection> findAllProjectedBy();
}
When I retrieve the data with findAllProjectedBy the result contains too many rows. It looks like the returned data is the result of a join query similar to:
select p.id, p.name, p.lastname, ci.id, ci.person_id, ci.description
from person p
join contact_info ci on ci.person_id = p.id
For example for this data set:
insert into person (id,name,lastname,ssh_key) values (1,'John','Wayne','SSH:KEY');
insert into contact_info (id, person_id, description) values (1,1,'+1 123 123 123'), (2,1,'john.wayne#west.com');
The findAllProjectedBy method returns 2 objects (incorrectly) and the standard findAll returns 1 object (correctly).
Full project is here
I've done some debugging and it seems that the problem is with the jpa query.
The findAll method uses this query:
select generatedAlias0 from Person as generatedAlias0
The findAllProjectedBy uses this query:
select contactInfoList, generatedAlias0.id, generatedAlias0.name, generatedAlias0.lastname from Person as generatedAlias0
left join generatedAlias0.contactInfoList as contactInfoList
Does anyone know how to fix this invalid behaviour?
A quick fix for this problem is described here:
https://jira.spring.io/browse/DATAJPA-1173
You need to describe one of the single projection attributes with a #Value annotation. For the example posted above you will end up with:
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
public interface PersonProjection {
#Value("#{target.id}")
Integer getId();
String getName();
String getLastname();
List<ContactInfo> getContactInfoList();
}

Spring data JPA - Exclude ID column from one entity parameter

I have two entities :
#Entity
public class Car {
#Id
private Long id;
#OneToOne
private Engine engine;
}
and the other one :
#Entity
public class Engine {
#Id
private Long id;
#Column
private String value1;
#Column
private String value2;
}
In my jpaRepositoy interface, i would like to do :
public interface CarRepository extends JpaRepository<Car, Long> {
public Car findByEngine(Engine engine);
}
But this method doesn't return my entity stored, because I created my Engine doing :
Engine engine = new Engine("someValue", "someValue");
without setting engine's id which is stored in database.
So I would like to know if it is possible exclude a column like id ?
If no, is the only way to do this is :
#Query("SELECT c FROM Car c WHERE c.engine.value1 = :value1 and c.engine.value2 = :value2")
findByEngine(#Param("value1") String value1, #Param("value2") String value2)
?
Related question : If I have OneToMany relationship instead of OneToOne, like
#Entity
public class Car {
#Id
private Long id;
#OneToMany
private List<Engine> engines;
}
How can I do this request to have something like (still without id column) :
public Car findByEngines(List<Engine> engines);
Thanks a lot !
This #Query("SELECT c FROM Car c WHERE c.value1 = :value1 and c.value2 = :value2") is not correct jpql query for your scenario, You do not have value1 and value2 in Car entity.
Correct one would be:
#Query("SELECT c FROM Car c WHERE c.engine.value1 = :value1 and c.engine.value2 = :value2").
You can try this method Name, I think that will work:
findByEngineValue1AndEngineValue2(String value1, String value2)
but for list one, i do not think you can make it up with just method name.

How Join hibernate Value objects using HQL query?

Hi i'm New to write HQL Query please help me.....
my Hibernate have three ValueObjects ie.
#Entity
#Table(name="user")
public class UserVO {
#Id
#Column(name="S_ID")
private String s_id;
#Column(name="FIRSTNAME")
private String firstName;
private String email;
}
CourseVO class
#Entity
#Table(name="course")
public class CourseVO
{
#Id
#Column(name="S_ID")
public String s_id;
#Column(name="NAME")
public String name;
}
Skillset VO
#Entity
#Table(name="skillset")
public class SkillsetVO
{
#Id
#Column(name="S_ID")
public String s_id;
#Column(name="COURSE_ID")//Foreign Key "USER"
public String course_id;
#Column(name="USER_ID")//Foreign key "COURSE"
public String user_id;
#Column(name="TEACH_EXP")
public String teach_Exp;
}
Now How to get Values of FirstName,NAME,TEACH_EXP values using EMAIL of USER table using HQL query
If you want to use join syntax in HQL you must work out your mapping accordingly as joins are enabled by mapping.
#Entity class A { #OneToMany private List<B> bs; }
#Entity class B { #Basic int n; }
Enables
select b from A a inner join a.b where a = :id
But with your mapping this is not possible. Also bear in mind that in terms of efficiency most of the RDBMs will perform an inner join on a where a.id = b.id.
select u.firstName, c.name, s.teach_Exp
from UserVO u, CourseVO c, SkillsetVO s
where
u.s_id = s.user_id
and c.s_id = s.course_id
and u.email = :email
But I think that you must review you association. Since looks to me that SkillsetVO.user_id should be SkillsetVO.User (an association to a UserVO entity and same for CourseVO).

Categories