I have an entity "Post" with this property:
#ElementCollection
#CollectionTable(name ="tags")
private List<String> tags = new ArrayList<>();
Then i have a native select query with a group by. The problem is now how can i select the property tags?
My select query:
Query query = em.createQuery("SELECT p.id,MAX(p.createdAt),MAX(p.value) FROM Post p JOIN p.tags t WHERE t IN (?1,?2,?3) GROUP BY p.id ORDER BY COUNT(p) DESC");
/* ...
query.setFirstResult(startIndex);
query.setMaxResults(maxResults);
List<Object[]> results = query.getResultList();
List<Post> posts = new ArrayList<>();
for (Object[] result : results) {
Post newPost = new Post();
newPost.setId(((Number) result[0]).longValue());
newPost.setCreatedAt((Date) result[1]);
newPost.setValue((String) result[2]);
posts.add(newPost);
}
return posts;
how to select the property tags?
Don't know if it will help, but in JPA2.1 Spec, part 4.4.6 Collection Member Declarations, you can do that:
SELECT DISTINCT o
FROM Order o, IN(o.lineItems) l
WHERE l.product.productType = ‘office_supplies’
So I guess with your case, you could try:
SELECT p.id,MAX(p.createdAt),MAX(p.value), t
FROM Post p, IN(p.tags) t
WHERE t IN (?1,?2,?3)
GROUP BY p.id, t
ORDER BY COUNT(p) DESC
Note: I added t to the GROUP BY, since it would not work with the query without using an aggregate function.
Related
Actually ,I want to extract generic data from EF table without using models but unfortunately two columns with same name from different database crashed...
Here is the query
var query = (from jbct in entities.Table1.AsEnumerable()
join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id
select new
{
jbct.id,
p.id
}).ToList();
try use a dynamic name
var query = (from jbct in entities.Table1.AsEnumerable()
join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id
select new
{
Id1 = jbct.id,
Id2 = p.id
}).ToList();
Now I've found now my solution to usie dictionary class
Dictionary with object as value
var query = (from jbct in entities.Table1.AsEnumerable() join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id select new Dictionary<String, Object>
{
{"jbct_id", jbct.id},
{"p_id", p.id}}
).ToList();
Thanks
I have a problem in JPQL cascade query with eclipselink2.5
please see code
Entity code
public class Category{
...
#JoinColumn(name = "parent_category", referencedColumnName = "id")
#ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER,optional = true)
private Category parentCategory;
...
}
JPQL code
String jpql = "select o from Category o order by o.parentCategory.sort ASC";
problem
the problem is this JPQL return list does not include 'o' if 'o.parentCategory' is null.
please see this table http://i.stack.imgur.com/xsXvk.jpg
the return list only rows id is 2,3,4 .
because the column parent_category is null, I lost rows 1,5,6
the correct result should be return all rows
Looking forward to your help!
Using o.parentCategory.sort in the order by clause forces an inner join which filters nulls. If you want nulls included, you will need to use an explicit outer join in the query:
"select o from Category o outer join o.parentCategory parentCategory order by parentCategory.sort ASC"
I faced with a strange thing with native queries:
If I'm trying to use named native query like the following
#NamedNativeQuery(name = "native_count_avg_guest_quizzes", resultClass = java.math.BigDecimal.class, query = "select avg(c) as r from ((select count(*) as c from user_quiz uq join user u on (uq.user_id = u.id) where u.status = 'temporary' group by u.id) as res)")
The application cannot run and I have
org.hibernate.HibernateException: Errors in named queries: native_count_avg_guest_quizzes_
But the same query works fine if I do not use NamedNativeQuery and merely create a dynamic native query like the following:
entityManager.createNativeQuery(
"select avg(c) as r from ((select count(*) as c from user_quiz uq join user u on (uq.user_id = u.id) where u.status = 'temporary' group by u.id) as res)")
.getSingleResult()
Why? What I'm doing wrong with NamedNativeQuery? Thanks
Update:
Entity class is as following
#Entity
#Table(name = "user_quiz")
#NamedNativeQueries({
#NamedNativeQuery(name = "native_count_avg_guest_quizzes", resultClass = java.math.BigDecimal.class, query = "select avg(c) as r from ((select count(*) as c from user_quiz uq join user u on (uq.user_id = u.id) where u.status = 'temporary' group by u.id) as res)")
})
#NamedQueries({
#NamedQuery(name = "list_clients_quizzes", query = "select uq from UserQuiz uq where uq.quiz.client.id = :clientId"),
.......
})
public class UserQuiz extends Measurable {
.......
}
createNativeQuery is used for native SQL query language that mean DB can understand and execute that query (Eg, select * from some_table where id = '0001');
It may cause DB dependency. Now you are using JPQL language, that's why, use createQuery() or createNameQuery() with #NameQuery annotation sing.
Example :
#NameQuery
#NamedQuery(name = "findAllEmployee", query = "select e from Employee e")
#Entity
public class Employee {
#Id int id;
String name;
// ...
}
Query query = em.createNamedQuery("findAllEmployee");
query.getResultList()
Dynamic
Query query = em.createQuery("select e from Employee e");
query.getResultList()?
*Native
Query query = em.createNativeQuery("SELECT * FROM EMPLOYEE_TBL");
query.getResultList()?
Delete resultClass from #NamedNativeQuery.
See https://stackoverflow.com/a/9763489
For NamedNativeQueries you can only use resultClass when the result actually maps to an Entity.
I want to do something like this:
select count(*) from (select ...)
(As it would be in SQL), but in JPA.
Any ideas on how I would do it?
I stumbled upon this issue as well. I would ultimately like to execute the following JPQL:
SELECT COUNT(u)
FROM (
SELECT DISTINCT u
FROM User u
JOIN u.roles r
WHERE r.id IN (1)
)
But this wasn't possible, also not with criteria API. Research taught that this was just a design limitation in JPA. The JPA spec states that subqueries are only supported in WHERE and HAVING clauses (and thus not in the FROM).
Rewriting the query in the following JPQL form:
SELECT COUNT(u)
FROM User u
WHERE u IN (
SELECT DISTINCT u
FROM User u
JOIN u.roles r
WHERE r.id IN (1)
)
using the JPA Criteria API like as follows:
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<User> u = query.from(User.class);
Subquery<User> subquery = query.subquery(User.class);
Root<User> u_ = subquery.from(User.class);
subquery.select(u_).distinct(true).where(u_.join("roles").get("id").in(Arrays.asList(1L)));
query.select(cb.count(u)).where(cb.in(u).value(subquery));
Long count = entityManager.createQuery(query).getSingleResult();
// ...
has solved the functional requirement for me. This should also give you sufficient insight into solving your particular functional requirement.
This should do the trick (If you want to use JPA criteria API):
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<Entity> root = query.from(Entity.class);
//Selecting the count
query.select(cb.count(root));
//Create your search criteria
Criteria criteria = ...
//Adding search criteria
query.where(criteria);
Long count = getEntityManager().createQuery(query).getSingleResult();
On the other hand, if you want to use JP-QL, the following code should do the trick:
//Add the where condition to the end of the query
Query query = getEntityManager().createQuery("select count(*) from Entity entity where...")
Long count = query.getSingleResult();
Use the following snippet to count rows for a given Criteria Query:
public static Query createNativeCountQuery(EntityManager em, CriteriaQuery<?> criteriaQuery) {
org.hibernate.query.Query<?> hibernateQuery = em.createQuery(criteriaQuery).unwrap(org.hibernate.query.Query.class);
String hqlQuery = hibernateQuery.getQueryString();
QueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator(
hqlQuery,
hqlQuery,
Collections.emptyMap(),
em.getEntityManagerFactory().unwrap(SessionFactoryImplementor.class),
null
);
queryTranslator.compile(Collections.emptyMap(), false);
String sqlCountQueryTemplate = "select count(*) from (%s)";
String sqlCountQuery = String.format(sqlCountQueryTemplate, queryTranslator.getSQLString());
Query nativeCountQuery = em.createNativeQuery(sqlCountQuery);
Map<Integer, Object> positionalParamBindings = getPositionalParamBindingsFromNamedParams(hibernateQuery);
positionalParamBindings.forEach(nativeCountQuery::setParameter);
return nativeCountQuery;
}
private static Map<Integer, Object> getPositionalParamBindingsFromNamedParams(org.hibernate.query.Query<?> hibernateQuery) {
Map<Integer, Object> bindings = new HashMap<>();
for (var namedParam : hibernateQuery.getParameterMetadata().getNamedParameters()) {
for (int location : namedParam.getSourceLocations()) {
bindings.put(location + 1, hibernateQuery.getParameterValue(namedParam.getName()));
}
}
return bindings;
}
I have tried to write a query statement with a subquery and an IN expression for many times. But I have never succeeded.
I always get the exception, " Syntax error near keyword 'IN' ", the query statement was build like this,
SELECT t0.ID, t0.NAME
FROM EMPLOYEE t0
WHERE IN (SELECT ?
FROM PROJECT t2, EMPLOYEE t1
WHERE ((t2.NAME = ?) AND (t1.ID = t2.project)))
I know the word before 'IN' lose.
Have you ever written such a query? Any suggestion?
Below is the pseudo-code for using sub-query using Criteria API.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
Root<EMPLOYEE> from = criteriaQuery.from(EMPLOYEE.class);
Path<Object> path = from.get("compare_field"); // field to map with sub-query
from.fetch("name");
from.fetch("id");
CriteriaQuery<Object> select = criteriaQuery.select(from);
Subquery<PROJECT> subquery = criteriaQuery.subquery(PROJECT.class);
Root fromProject = subquery.from(PROJECT.class);
subquery.select(fromProject.get("requiredColumnName")); // field to map with main-query
subquery.where(criteriaBuilder.and(criteriaBuilder.equal("name",name_value),criteriaBuilder.equal("id",id_value)));
select.where(criteriaBuilder.in(path).value(subquery));
TypedQuery<Object> typedQuery = entityManager.createQuery(select);
List<Object> resultList = typedQuery.getResultList();
Also it definitely needs some modification as I have tried to map it according to your query. Here is a link http://www.ibm.com/developerworks/java/library/j-typesafejpa/ which explains concept nicely.
Late resurrection.
Your query seems very similar to the one at page 259 of the book Pro JPA 2:
Mastering the Java Persistence API, which in JPQL reads:
SELECT e
FROM Employee e
WHERE e IN (SELECT emp
FROM Project p JOIN p.employees emp
WHERE p.name = :project)
Using EclipseLink + H2 database, I couldn't get neither the book's JPQL nor the respective criteria working. For this particular problem I have found that if you reference the id directly instead of letting the persistence provider figure it out everything works as expected:
SELECT e
FROM Employee e
WHERE e.id IN (SELECT emp.id
FROM Project p JOIN p.employees emp
WHERE p.name = :project)
Finally, in order to address your question, here is an equivalent strongly typed criteria query that works:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> c = cb.createQuery(Employee.class);
Root<Employee> emp = c.from(Employee.class);
Subquery<Integer> sq = c.subquery(Integer.class);
Root<Project> project = sq.from(Project.class);
Join<Project, Employee> sqEmp = project.join(Project_.employees);
sq.select(sqEmp.get(Employee_.id)).where(
cb.equal(project.get(Project_.name),
cb.parameter(String.class, "project")));
c.select(emp).where(
cb.in(emp.get(Employee_.id)).value(sq));
TypedQuery<Employee> q = em.createQuery(c);
q.setParameter("project", projectName); // projectName is a String
List<Employee> employees = q.getResultList();
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> empleoyeeRoot = criteriaQuery.from(Employee.class);
Subquery<Project> projectSubquery = criteriaQuery.subquery(Project.class);
Root<Project> projectRoot = projectSubquery.from(Project.class);
projectSubquery.select(projectRoot);
Expression<String> stringExpression = empleoyeeRoot.get(Employee_.ID);
Predicate predicateIn = stringExpression.in(projectSubquery);
criteriaQuery.select(criteriaBuilder.count(empleoyeeRoot)).where(predicateIn);
You can use double join, if table A B are connected only by table AB.
public static Specification<A> findB(String input) {
return (Specification<A>) (root, cq, cb) -> {
Join<A,AB> AjoinAB = root.joinList(A_.AB_LIST,JoinType.LEFT);
Join<AB,B> ABjoinB = AjoinAB.join(AB_.B,JoinType.LEFT);
return cb.equal(ABjoinB.get(B_.NAME),input);
};
}
That's just an another option
Sorry for that timing but I have came across this question and I also wanted to make SELECT IN but I didn't even thought about double join.
I hope it will help someone.