let's say I have the next entity or object:
class Person {
BigInteger cardNumber;
String name;
int age;
Address address;
}
Then, I have a List<Person> and I want to find the youngest person based on the cardNumber and name. So, I'd like to write a query similar to this:
#Query("SELECT p FROM Person p WHERE p.cardNumber = :myPerson.cardNumber AND p.name LIKE :myPerson.name ORDER BY p.age ASC")
public List<Person> find(#param("myPerson") List<Person> personList);
My problem is that I'm not so sure how to tackle this, and what approach to use. I've tried passing two collections, List<String> names and List<BigInteger> cardNumbers and the query was something like this:
#Query("SELECT p FROM Person p WHERE p.cardNumber IN (:cardNumbers) AND p.name IN (:names) ORDER BY p.age ASC")
public List<Person> find(#param("cardNumbers") List<BigInteger> cardNumbers, #param("names") List<String> names);
The problem, I need to use the name and the cardNumber as a single value to compare because, they both work as a primary key. I tried to CONCAT(name, cardNumber) and pass to the method a list of strings with the name.concat(cardNumber.toString(()) value but, I found that the JPQL turns the BigInteger in a number like this 1.00 so, to make it work I need to do something like this name.concat(cardNumber.toString(() + ".00"). That way, it works but, I can't hardcode that mapping from BigInteger to String.
Any advice is appreciated. I just want to find a way to pass the collection of the object rather than concatenate those strings in my code and then pass them to the query method.
Thank you.
Related
Let's make a journey...
What I want to achieve is
SELECT * FROM people WHERE interest->'interests' ?| ARRAY['sport','cars'];
into my Repository defined as
public interface PeopleRepository extends CrudRepository<People, UUID> {
#Query("SELECT * FROM people where interest->'interests' ??| :array::text[] ")
List<People> findByInterest(#Param("array") String interest);
and finally select interests, using the method in this way
findByInterest("{foo, beer}")
This is what I achieved after a day of tests and
IMHO is really MEH
I think out of there, a nicest solution is possible
(without sql cast and string concatenation in runtime)
Could you help with a more "clean code" solution?
(Sorry, for the long post)
Update
I will elaborate a little bit better my question.
I'm searching for something like
#Query("SELECT * FROM people where interest->'interests' ??| :array::text[] ")
List<People> findByInterest(#Param("array") List<String> interest);
is this possible ?
JSON array elements strores data in the following way
{
"interests" : ["sport", "cars"]
}
So if you directly java list it does not work, so one option is convert java array into a string which can be looked at as json array like ["sport", "cars"] or
use jsonObject used to create json array like below
JSONArray interests = new JSONArray();
a.add(0, "sport");
a.add(0, "car");
findByInterest(interests.toString())
#Query("SELECT * FROM people where interest->'interests' ??| :array::text[] ")
List<People> findByInterest(#Param("array") String interest);
#Entity
Student {
Long id;
String name;
}
Let's say I have a list of 10 Students List<Student> studentList = new ArrayList<>(); stored in a list somewhere in my app.
And I have a list of 20 entities I have stored in DB previously:
List<Student> studentsDbList = StudentRepo.findAll()
I would like to find out which of these 20 are not in the studentList, and delete them from database in the most efficient way without clearing whole db.
I can't find nothing similar on hibernate which allows me to do this with one method call, but I assume this is a trivial problem which has been solved numerous times, and I simply doesn't comprehend hibernate enough to solve it with some oneliner(
Any suggestions here?
You can filter database entities by which are not in App and get the id of those Student those you want to delete using Stream API
List<Long> ids = studentsDbList.stream()
.filter(e -> !studentList.contains(e))
.map(e -> e.getId())
.collect(Collectors.toList());
then delete by ids from the database by using this on the repository
void deleteByIdIn(List<Long> ids);
And call with those student ids you want to delete
studentRepo.deleteByIdIn(ids);
Note: Override equals in Student class
Another better way is
List<Long> ids = studentList.stream()
.map(e -> e.getId())
.collect(Collectors.toList());
#Query(value = "DELETE FROM Student s WHERE s.id NOT IN (:ids)")
void deleteByIdIn(#Param("ids") List<Long> ids);
findAll() doesn't seem like optimal way and it's a code smell. I would only fetch id's from db. Add this methods to student repository:
#Query("select s.id from Student s")
List<Long> getAllIds();
void deleteByIdIn(List<Long> ids);
Then make a diff on id's list and remove by ids:
ArrayList<Long> studentIdsToRemove = new ArrayList<>(studentIdsFromDB);
studentIdsToRemove.removeAll(studentIds);
studentRepo.deleteByIdIn(studentIdsToRemove);
I need to get count and sum of my ObjectEntity in one Query form Repository Layer. Count is a Long value, but sum is Double value. It possible to locate result in one DTO Object from Repository method or locate it numeric list object e.g. List ?
Query method look like below
#Query(value = "Select count(f), sum(f.valueToPay) from ObjectEntity f ")
Object[] getData();
POJO Object
#Data
public class ObjectDTO {
Double value;
Long quantity;
}
If I'm understanding the question correctly, you just need the results of the query to go into an object that will give you meaningful and consistent variable names.
All you should need to do is Change Object[] to ObjectDTO so that you have
#Query(value = "Select count(f), sum(f.valueToPay) from ObjectEntity f ")
ObjectDTO getData();
Right now you are mapping to an object array instead of the actual object you want to use.
Use a JPQL Constructor Expression:
#Query(value = "Select NEW com.company.pathToYourDto.ObjectDTO(count(f), sum(f.valueToPay)) from ObjectEntity f ")
ObjectDTO getData();
I need to query on my database (postgres) like this:
Entity:
class Cat{
int id;
String name;
}
main class:
int [] idCats = {1,2,7,5,8,4,9,10,12,14};
for(int id : idCats){
Cat cat = session.load(Cat,id);
(do something with cat, according your name)
}
But, this approach generates to many sqls. Considering i'll search almost all ids, there's a
way to bring all objects e search on it using criteria. Without implement by myself.
You can use the second level cache feature of hibernate. But if your application is simple and you just want to fetch a cat with its id, then store the result of the query in a hashmap like
Map<Integer, Cat> mapCats = new HashMap<Integer, Cat>();
You can use the for loop to iterate over the list from DB.
Map<Integer, Cat> mapCats = new HashMap<Integer, Cat>();
for(Cat oneCat: listCats) {
mapCats.put(oneCat.id, oneCat);
}
Then retrieve using
mapCats.get(catid);
Consider a class:
class Employee{
Integer empId,
//many other fields
}
I need a DAO method as shown below
List<Integer> getAllEmployeeIds(){
//??
}
I dont want List<Employee> and (NEW EDIT) Set<Intger>
How can i do that in hibernate?Am using hbm files for mapping
Like this. Also, I recommend use querydsl to make it type-safe.
List<Integer> getAllEmployeeIds(){
return (List<Integer>)createQuery("select e.empId from Employee e").list();
}
use an hql query and do something like
String hql = "select E.empId from Employee E";
Query query = session.createQuery(hql);
List<Integer> ids = query.list();
follow the documentation from here.