Are this JDOQL same as the following SQL?
Query query = pm.newQuery(Vote.class, ":p.contains(personId)");
if (startDate != null) {
query.setFilter("personId == listOfIds && createdDate > startDateParam");
query.declareParameters("java.util.List listOfIds, java.util.Date startDateParam");
}
else {
query.setFilter("personId == :listOfIds");
}
query.setOrdering("createdDate desc");
List<Vote> list = (List<Vote>) query.execute(listOfIds, startDate);
SELECT * FROM VOTE
WHERE persionID IN (id1, id2..)
AND createdDate > '2011-07-11'
ORDER BY createdDate desc;
Yes. Bear in mind that 'in' queries translate to multiple underlying datastore queries, and so aren't particularly efficient - if you can avoid them, do.
Related
Currently I am doing it like this:
List<Table1Entity> findAllMatchingEntities(Table1Entity table1Entity) {
String queryString = "SELECT table1.* FROM table1 "
+ "JOIN table2 t2 ON table1.id=t2.table1_id";
if (table1Entity.getName() != null) {
queryString +=" where name like ?";
}
Query query = em.createNativeQuery(queryString, Table1Entity.class);
if (table1Entity.getName() != null) {
query.setParameter(1, table1Entity.getName())
}
return query.getResultedList();
}
If I want to check more parameters in this join this will quickly turn into a lot of if statements and it would be really complicated to set parameters correctly.
I know I can check parameters with criteria Builder API like this:
if(table1Entity.getName() != null) {
table1EntitySpecification = (root, query, criteriaBuilder)
-> criteriaBuilder.like(
criteriaBuilder.lower(root
.get("name")),
("%" + table1Entity.getName() + "%")
.toLowerCase());;
}
and after that get them all with:
findAll(table1EntitySpecification) with findAll from simpleJPARepository. Now I can chain them together with .or or .and etc. and avoid setting the parameter and checking for null second time.
But how do I do join with criteria APi?
I know I can have in my #Repository something like this:
#Query(value = "SELECT table1.* FROM table1 JOIN table2 t2 ON table1.id=t2.table1_id", nativeQuery = true)
List<Table1Entity> findAllMatchingEntities(Table1Entity table1Entity);
But since name is optional (can be null) I can't just leave it in #Query.
What is the best solution here to avoid using native query and in case of having to check many parameters to avoid using if statements?
I don't know if I fully get your question, but regarding the possibility of nulls, and using the CRUD repository, you can always do a null check before like:
#Query(value = "SELECT table1.* FROM table1 JOIN table2 t2 ON table1.id=t2.table1_id WHERE table1.id is not null", nativeQuery = true)
List<Table1Entity> findAllMatchingEntities(Table1Entity table1Entity);
Depending on what you are trying to achieve, you can always compose the query with similar checks like (not related to your code):
#Query("SELECT c FROM Certificate c WHERE (:id is null or upper(c.id) = :id) "
+ "and (:name is null or upper(c.name) = :name)")
List<Table1> findStuff(#Param("id") String id,
#Param("name") String name);
I have an jpql query inside a JpaRepository like this:
#Query("select l from LogEntity l where l.codePackage = :codePackage and l.codeFile = :codeFile order by l.id desc")
public Page<LogEntity> findSimilarAngularLog (#Param("codePackage") String codePackage, #Param("codeFile") String codeFile, Pageable pageRequest);
The variable codePackage and codeFile can be NULL. But hibernate is always making something like
... where l.codePackage=? and l.codeFile=? ...
out of it. So if one or both of them are NULL, then there is l.codeFile=NULL and not l.codeFile IS NULL. And then he does not find anything at all.
If I copy the hibernate generated sql string to my MySQL console and change the =NULL to IS NULL, he will find everything.
So how do I change the behavior of hibernate jpa, so that in my #Query String the NULL will be treated correctly.
thanks a lot and greetings
You can use the below query for that:
#Query("select l from LogEntity l where ((:codePackage is null and l.codePackage is null) or l.codePackage = :codePackage) and ((:codeFile is null and l.codeFile is null) or l.codeFile = :codeFile) order by l.id desc")
But wouldn't that be a good idea to make hql through the logic rather than using it like the named queries?
A better logic would be to use an if condition, like,
if(codePackage == null) {
query += " l.codePackage is null ";
}
else {
query += " l.codePackage = :codePackage ";
}
***code***
//query execution code
WHERE ((:param is null and t.field is null) or t.field = :param)
#Query("select l from LogEntity l where ((:codePackage is null and l.codePackage is null) or l.codePackage = :codePackage ) and ((:codeFile is null and l.codeFile is null) or l.codeFile = :codeFile ) order by l.id desc")
I have a query I would write in older Hibernate (utilising the SessionFactory bean). However, I have shifted to Spring Boot and am now utilizing the JPA 2 which is essentially seems like a layer of abstraction over Hibernate. Could anyone guide me on as to how to add restrictions? I believe I will now have to use the EntityManager bean with JPA. Here is the older query.
#Override
#SuppressWarnings("unchecked")
public List<Party> queryPartiesBetweenDates(Date startDate, Date endDate, String sortBy, Integer count) {
Criteria criteria = getCurrentSession().createCriteria(Party.class);
if (startDate != null) {
criteria.add(Restrictions.ge("startDate", startDate));
}
if (endDate != null) {
criteria.add(Restrictions.lt("endDate", endDate));
}
if (count != null) {
criteria.setMaxResults(count);
}
if (sortBy == null || !sortBy.equals("distance")) {
criteria.addOrder(Order.asc("startDate"));
}
return criteria.list();
}
Thanks!
The CriteriaBuilder is quite a bit more verbose than the native hibernate Restriction API, the primary reason is that it is fully typed when you use the MetaModel, which means the code will not compile if the type or name of a column causing a query to be invalid.
Here is an example that does not use the generated MetaModel classes, and mostly resembles the old Hibernate code.
EntityManager em = emf.createEntityManager(); // or injected
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Party> query = cb.createQuery(Party.class);
Root<Party> partyRoot = query.from(Party.class);
query.select(partyRoot);
Predicate predicate = null;
Path<Date> startDatePath = partyRoot.<Date>get("startDate");
if (startDate != null) {
predicate = cb.greaterThanOrEqualTo(startDatePath, startDate);
}
if (endDate != null) {
Predicate additionalPredicate = cb.lessThanOrEqualTo(partyRoot.<Date>get("endDate"), startDate);
if (predicate == null) {
predicate = additionalPredicate;
} else {
predicate = cb.and(predicate, additionalPredicate);
}
}
query.where(predicate);
if (sortBy == null || !sortBy.equals("distance")) {
query.orderBy(cb.asc(startDatePath));
}
return em.createQuery(query).setMaxResults(count).getResultList();
If you have many Predicates, it may be a good idea to add them to a list, or create a utility method for handling them.
I have the following criteria query:
String cat = "H";
Criteria criteria = currentSession().createCriteria(this.getPersistentClass()).
add(Restrictions.ne("category", cat)).
createAlias("employees", "emp").
createAlias("emp.company", "company");
Disjunction disjunction = Restrictions.disjunction();
for(Region r: regions){
disjunction.add(Restrictions.eq("company.region", r));
}
criteria.add(disjunction);
if(status != null) {
criteria.add(Restrictions.eq("status", status));
}
if (period != null) {
criteria.add(Restrictions.eq("period", period));
}
criteria.setProjection(Projections.groupProperty("id")) //this line was added to try to "fix" the error, but it still happened.
criteria.addOrder(Order.asc("id"));
I guess a query that explains my criteria query could be:
select n.* from NOMINATION n
join NOMINEE i on n.NOM_ID = i.NOM_ID
join EMPLOYEE e on e.EMP_ID = i.EMP_ID
join COMPANY c on c.COMPANY_CODE = e.COMPANY_CODE
where n.CATEGORY_CODE!='H' and (c.REGION_ID = ? or c.REGION_ID = ? or c.REGION_ID = ?) and n.STATUS_ID = ? and n.PERIOD_ID = ?
order by n.NOM_ID
What I am trying to do here, is pretty confusing but for the most part it works except when I add this specific line (though the query works fine):
criteria.addOrder(Order.asc("id"));
and then I get error:
java.sql.SQLException: Column "NOMINATION.NOM_ID" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.
Which I suspect is something that has to do with SQL-SERVER. I am already grouping by id. So what am I doing wrong here, or should I just use HQL?
Your current query seems to be a simple Query which doesn't have any group function used or not a group by query. According to your current requirements you do not have to use this line.
criteria.setProjection(Projections.groupProperty("id")).addOrder(Order.asc("id"));
Or you have to modify your sql statements.
For example, I have a statement
"SELECT * FROM Reports WHERE StartDate >= ? WHERE EndDate <= ? AND Performer = ?"
But sometimes some input fields on the web page are not filled, so I have to not take into account this conditions. i.e. I have no startdate filled, so statement must be
"SELECT * FROM Reports WHERE EndDate <= ? AND Performer = ?"
There are 3 different conditions. So, Do I have to write 8 different statements and DAO methods to accomplish the task? Really? Maybe there are other solutions?
Edit: I use MySQL/
Change your SQL to cater for nulls. Because you have not told us which database you are using, I will use "vanilla" SQL:
SELECT *
FROM Reports
WHERE (EndDate <= ? OR ? is null)
AND (Performer = ? OR ? is null)
Pass the parameters in twice each.
The other choice is to alter the SQL based on parameters being null (for example omitting Performer = ? from the where clause), but this can require a lot of code and testing. Iwould use the adaptable SQL and if it performs badly, then attempt something more advanced.
You dont need 8 different statements. You can build the query using if statements. For e.g.,
String query = "SELECT * FROM Reports where true";
if(startDate != null)
query = query + " and startDate <= ?";
if(endDate != null)
query = query + " and endDate <= ?";
if(performer != null)
query = query + " and performer = ?";
Hope it works for you.
No Prepared statement cannot exclude contions on its own. The query as to be contructed to avoid unnecessary conditions.
You can generate SQL using the code :
StringBuilder whereClause = new StringBuilder();
String and = "";
if(EndDate == null || EndDate.length == 0)
{
whereClause.append(your condition);
and = " and";
}
if(StartDate == null || StartDate.length == 0)
{
whereClause.append(and).append(your condition);
and = " and";
}
if(Performer == null || Performer.length == 0)
{
whereClause.append(and).append(your condition);
}
and based on you generated query you need to set the parameters to the prepared statement.