I have two objects.
#Entity
class Person extends Model {
...
#OneToOne
Category category;
}
#Entity
class Category extends Model {
...
}
I need to get the 5 most used categories. How can I do that ?
Thanks,
EDIT : Solution
List<Object[]> c = Category.find(
"SELECT p.categorie, count(p.id) FROM Person p " +
"GROUP BY p.category ORDER BY count(p.category) DESC").fetch(2);
Your JPQL query would be something like this:
SELECT p.category, COUNT(p.category)
FROM Person p
GROUP BY p.category
ORDER BY count(p.category) DESC
And you'd do query.setMaxResults(5) also.
select category.id, count(person.id)
from Person person
inner join person.category category
group by category.id
order by count(person.id) desc
And before executing this query, call setMaxResults(5) on the Query object.
Related
I have an entity ParentEntity defined as
public class ParentEntity
{
private long id;
private List<ChildEntity> children;
#OneToMany(mappedBy = "parent")
public List<ChildEntity> getChildren()
{
return children;
}
}
and
public class ChildEntity
{
private ParentEntity parent;
private String code;
...
}
I understand that using the annotation #FilterJoinTable I can filter parents have a child with a specific code, defined as filter parameter, but
I'm trying to figure how to filter by annotations the parents that have no childern or a child with code as the parameter defined.
Something like SQL:
select * from ParentEntity p left join ChildEntity c
on p.id=c.parent_id
where p.id in (select p.id from ParentEntity p join ChildEntity c
on p.id=c.parent_id where c.code=:code)
OR p.id not in ( select parent_id from ChildEntity )
or HQL:
select p from ParentEntity p join fetch p.childen c
where p.id in (select p.id from ParentEntity p join p.childen c where c.code=:code)
OR p.id not in ( select c.parent.id from ChildEntity c )
This because I've a lot of classes with Parent or List<Parent> as property and each one retreives the ChildEntity too, always with the same condition above, so I wouldn't rewrite the same condition on all the queries.
Have you any idea?
Thanks
Filter clause is directly what goes to SQL where clause.
I think you could try something like:
#Filter(name = "childWithCode",
condition = "(exists (select 1 from ChildEntity ce where id = ce.parent_id and code='foobar'))")
public class ParentEntity { ...
The most flexible way is to simply use a query:
String code = ...;
Query query = session.createQuery(
"select p" +
" from ParentEntity p" +
" left join p.children c" +
" where c is null or c.code = :code"
);
query.setParameter("code", code);
List list = query.list();
Then whenever you need the filtered Parents, you run this DAO method.
This is more flexible, because there might be times when you want to retrieve Parents without children. Maybe a business case demands removing children, only to add them later. If you always filter out Parents with no children, then you won't be able to re-add children to those, right?
consider the following schema
#Entity
Class employee{
#OneToMany()
List<employee> manaagedEmps;
#OneToOne
employee manager;
}
how to write a query that get all the managed employee for a certain manager , direct(the list of managedEmps) and indirect (managed by managed employee).
It seems that JPA does not support recursive queries. Recently I solved the smilar problem by adding "path" field of type ltree (postgresql). Path is generated by adding id separated by dot to path of parent and path of root nodes is just id. With that field you are able to query subtree (direct and indirect employees) of some node (manager):
SELECT * FROM nodes WHERE path ~ '*.42.*{1,}'; /* for path of type ltree */
SELECT * FROM nodes WHERE path LIKE '%.42.%'; /* for path of type varchar */
The following JPQL query returns flat list of subs for employee with id 2.
List<Employee> subs = em.createQuery(
"SELECT e FROM Employee e LEFT JOIN FETCH e.subs WHERE e.path LIKE '%.' || ?1 || '.%'",
Employee.class
).setParameter(1, '2').getResultList();
//Returns a list of the managed employee of the manager with the specified ID.
#NamedQuery(name="queryName", query="SELECT p.managedEmps FROM employee p WHERE p.manager.uuid = :uuid")
I am using postgresql here.
I did this through native query like this:
Suppose following entity
#Entity
#Table(name = "employee")
public class Employee {
#Id
private Long id;
#ManyToOne
#JoinColumn(name = "parent_id")
private Employee parent;
}
Now, following query can be used to get all childs and sub childs under one manager recursively:
public interface IEmployeeRepository extends JpaRepository<Employee, Long> {
#Query(value = "with recursive subordinates as ("
+ " select e1.id as id, e1.parent_id as parent from employee e1 where e1.parent_id = :parentId"
+ " union"
+ " select e2.id, e2.parent_id from employee e2"
+ " inner join subordinates s on (s.id = e2.parent_id)"
+ " ) select * from subordinates", nativeQuery = true)
Collection<Employee2> getChilds(#Param("parentId") Long parentId);
public static interface Employee2 {
Long getId();
Long getParent();
}
}
Now, you have to convert this result Collection into List in your service layer. That's it.
References:
postgres recursive queries
Jpa Projections to get result
Hope this helps.
I usually prefer to offer some code, but in this case I think the article itself does a better job of explaining.
I have class Person containing field age, Class Student extends Person containing field class, and class Teacher extends Person and containing field salary.
I want to get all Person who are in class X, if they are Student, and earn 1500$, if they are Teacher, using the same jpql query. The query must return a list of Person. I can make two query and make a method that call both query and join the result but is there a better solution.
I hope I was able to explain
Use "TYPE" and JPA 2.1 "TREAT" to filter on the class.
"SELECT p from Person p where treat(p as Teacher).salary = 1500 or TYPE(p) = Student"
If you cannot use JPA 2.1, you can use a subquery on Teacher to return Teacher ids with salary=1500, and use the result in the main query.
"SELECT p from Person p where p.id in(SELECT t.id from Teacher t where t.salary=1500) or TYPE(p) = Student"
When I have the below query it will give me a list of Product.
List<Product>=
getCurrentSession().createQuery("SELECT p FROM Product p ").list();
What will it return when there is a join as below.
getCurrentSession().createQuery("SELECT p FROM Product p inner join ProductCategory pc where p.id=pc.id").list();
It should return List<Object[]> as a result. Please see this thread
And you should access your entities like
for (Object[]> result : query.list()) {
Product p = (Product) result[0];
ProductCategory pc = (ProductCategory) result[1];
}
SELECT p FROM Product p inner join ... something like that gives you a list of Products.
FROM Product p inner join ... something like that gives you a list of arrays.
This will return a list of objects. You will have to cast them in to Product
List list = session.createQuery("SELECT p FROM Product p inner
join ProductCategory pc where p.id=pc.id").list();
According to the documentation for javax.persistence.Query, you are going to get a List back. Why would you think it should be different?
This class casting from java.lang.object to model class doesn't work in any ways. Below is my code.
List<Contactinfo> listStudentInfo = new ArrayList<Contactinfo>();
//listStudentInfo = dataService.getAllStudent(studentInfo);
listStudentInfo = dataService.getStudentInfo();
System.out.println(listStudentInfo.size());
Contactinfo contactinfo = (Contactinfo)listStudentInfo.get(0);
But In hibernate, you don't need join if you have both Entity associated with by #Many-to-one or #One-to-one join annotation. Then you need to select one object only , you will automatically get access to other object via the join. Make sure you keep getter(), setter() method for the joining field. Hope this will clarify the situation.
I am starting to learn JPA, and have implemented an example with JPA query, based on the following native SQL that I tested in SQL Server:
SELECT f.StudentID, f.Name, f.Age, f.Class1, f.Class2
FROM Student f
LEFT OUTER JOIN ClassTbl s ON s.ClassID = f.Class1 OR s.ClassID = f.Class2
WHERE s.ClassName = 'abc'
From the above SQL I have constructed the following JPQL query:
SELECT f FROM Student f LEFT JOIN f.Class1 s;
As you can see, I still lack the condition OR s.ClassID = f.Class2 from my original query. My question is, how can I put it into my JPQL?
Write this;
SELECT f from Student f LEFT JOIN f.classTbls s WHERE s.ClassName = 'abc'
Because your Student entity has One To Many relationship with ClassTbl entity.
If you have entities A and B without any relation between them and there is strictly 0 or 1 B for each A, you could do:
select a, (select b from B b where b.joinProperty = a.joinProperty) from A a
This would give you an Object[]{a,b} for a single result or List<Object[]{a,b}> for multiple results.
Normally the ON clause comes from the mapping's join columns, but the JPA 2.1 draft allows for additional conditions in a new ON clause.
See,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#ON
Please see :
public interface YourDBRepository extends JpaRepository<Employee, Long> {
#Query("select new com.mypackage.myDTO(dep.empCode, dep.empName, em.EmployeeCode, em.EmployeeName) \n" +
"from Department dep\n" +
"left join Employee em\n" +
"on dep.DepartmentCode = em.DepartmentCode") // this is JPQL so use classnames
List<myDTO> getDeptEmployeeList();
}
You can also use CrudRepository and include #JoinColumn with FK table class in PK table class and have List return list and then do find operation to achieve the same.
In Department entity class:
#OneToMany
#Fetch(FetchMode.JOIN)
#JoinColumn(name="DEPT_CODE")
private List<Employee> employees;
CriteriaBuilder is yet another option.