Add SQL condition to CriteriaQuery - java

I need add something like Restrictions.sqlRestriction to CriteriaQuery. How to add SQL condition to CriteriaQuery?
My code:
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Installation> criteriaQuery = criteriaBuilder.createQuery(Test.class);
Root<Installation> root = criteriaQuery.from(Test.class);
criteriaQuery.select(root);

JPA Criteria allows function() to be used, or other clauses that have JPQL equivalents. Since you don't say what is the "SQL condition" then that's all that can be said. You certainly can't dump some random SQL into a JPQL filter for example

I am not sure that it can be done. I suggest you these 3 options:
Implement whatever you need to do in your Hibernate entity, but I guess you have already tried and are here looking for some other solution
Rework your entire query as SQL
A more creative one: define a new Hibernate entity on a database view doing the 'delicate' part of your query, and leave the rest to be managed via Criteria.

Solution for my case (call Oracle function 'bitand')
criteriaQuery.where(criteriaBuilder.notEqual(criteriaBuilder.function("bitand", Long.class, root.get(Test_.status).get(Status_.id), criteriaBuilder.parameter(Long.class, "status")),0));
TypedQuery<Installation> query = em.createQuery(criteriaQuery.select(root));
query.setParameter("status", 1L);

Related

fetching single column values in JPA

I want to get all the values from a particular column in JPA and store all values into a list. currently, I am using the below approach but I am getting records in something else format.can someone please help me out
Query q1 = factory.createNativeQuery("select * from booking_attendee where booking_id="+id);
List<String> em1=q1.getResultList();
return em1;
query otput
em=[[Ljava.lang.Object;#68606667, [Ljava.lang.Object;#2cd7f99a, [Ljava.lang.Object;#137a5a5, [Ljava.lang.Object;#a45cc1c, [Ljava.lang.Object;#61fdc06d, [Ljava.lang.Object;#72f5eee1, [Ljava.lang.Object;#4e536797]
If you want to create a native query for this, it is more about how to solve this in SQL. You do not say SELECT * which means all columns. You would have to say SELECT your_column_name to select only a specific column.
Query q1 = factory.createNativeQuery("SELECT your_column FROM booking_attendee");
List<String> em1 = q1.getResultList();
The WHERE clause could and should be defined with the parameter binding of JPA. There are several advantages concerning performance and SQL injection.
Named parameter binding is special to the persistence provider (e.g. Hibernate). The common way for JPA is using ? to let your code be portable to other providers.
Query q1 = factory.createNativeQuery("SELECT your_column FROM booking_attendee b WHERE b.booking_id = ?");
q1.setParameter(1, id);
List<String> em1 = q1.getResultList();
Native queries offer the possibilities to use original SQL. Like this, some features which are specific for your database could be used with this. Nevertheless, if you do not have very specific SQL code, you should also have a look in JPQL, the specific query language of JPA, and the JPA Criteria API which offers advantages when you want to refactor your code, shows errors during compile time and makes the dynamic creation of queries easier.

How to use Hibernate criteria without joining the sub-classes

I'm trying to use Hibernate criteria without joining the sub-classes. Here is my case:
Notification.hbm.xml has the relation:
<many-to-one name="myObject" class="MyObject" column="MY_OBJECT_UID" not-null="true" index="NOTIFICATIONS_OBJECT" foreign-key="NOTIFICATIONS_OBJECT"/>
my JAVA code:
1. Criteria criteria = session.createCriteria(Notification.class.getName());
2. criteria.createAlias("myObject", "myObject", CriteriaSpecification.LEFT_JOIN);
3. criteria.addOrder(Order.desc("myObject.name").ignoreCase());
4. List<Notification> res = (List<Notification>) criteria.list();
If i remove lines 2 and 3 i get the result without joining MyObject, but if i add them, then the query is massive and doing Join with all of MyObject sub classes (and there are many).
I need a solution to avoid those Hibernate joins. One join for MyObject is OK (although not necessary), but Join to every subClass of it, is bad.
What are my option here?
Thanks.
One solution is to use projection, to query only the field you need
ProjectionList properties = Projections.projectionList();
properties.add(Projections.property("property1").as( "property1"));
...
criteria.setProjection(properties);
criteria.setResultTransformer(new AliasToBeanResultTransformer(Notification.class));
You can map it, to you domain Object but its is better to map it to custom DTO like a NotificationDTO, because it won't be managed entity but simple pojo:
You won't be able to update/ delete it. But if you need the data in "read only" mode its the best solution.

Dynamic Named Query in Entity class using JPQL example

I have a named query as below;
#NamedQuery(name = "MyEntityClass.findSomething", query = "SELECT item FROM MyTable mytbl")
Now I want to append dynamic sort clause to this query (based on UI parameters)
Can I get an example using JPQL for doing the same (like how to set a dynamic ORDER BY in the Entity class)
I have already tried using CriteriaQuery, but was looking for a JPQL implementation now.
NamedQueries are by definition NOT dynamic, it is not correct to change them programmatically.
So the way to go is to create a JPQL query (but not a named query) like this:
TypedQuery<MyEntity> query = em.createdQuery("SELECT item FROM MyEntity item ORDER BY "+sortingCol, MyEntity.class);
On the other hand, if you REALLY want to use the named query, you could do that the following way:
#NamedQuery(name = "MyEntityClass.findSomething", query = MyEntity.NAMED_QUERY)
#Entity
public class MyEntity {
public static final NAMED_QUERY= "SELECT item FROM MyTable mytbl";
//+your persistent fields/properties...
}
//and later in your code
TypedQuery<MyEntity> query = entityManager.createQuery(MyEntity.NAMED_QUERY + " ORDER BY " + sortingCol, MyEntity.class);
Complementing for JPA 2.1
As of JPA 2.1 it is possible to define named queries programmatically.
This can be achieved using entityManagerFactory.addNamedQuery(String name, Query).
Example:
Query q = this.em.createQuery("SELECT a FROM Book b JOIN b.authors a WHERE b.title LIKE :title GROUP BY a");
this.em.getEntityManagerFactory().addNamedQuery("selectAuthorOfBook", q);
// then use like any namedQuery
Reference here
This can be useful, for instance, if you have the orderby field defined as a application parameter. So, when the application starts up or on the first run of the query, you could define the NamedQuery with the defined OrderBy field.
On the other side, if your OrderBy can be changed anytime (or changes a lot), then you need dynamic queries instead of NamedQuery (static). It would not worth to (re)create a NamedQuery every time (by performance).
#NamedQuery
Persistence Provider converts the named queries from JPQL to SQL at deployment time.
Until now, there is no feature to create/update the query with #NamedQuery annotation at runtime.
On the other hand, you can use Reflection API, to change the annotation value at runtime. I think It is not solution, also it is not you wanted .
em.createQuery()
Persistence Provider converts the dynamic queries from JPQL to SQL every time it is invoked.
The main advantage of using dynamic queries is that the query can be created based on the user inputs.

How to bulk delete from element collection in jpa

I'm using jpa 2.0 and I have the following entity:
#Entity
public class Folder{
#ElementCollection
#CollectionTable(name="folder_files")
private Set<String> files;
// .....
}
Given a file name, I would like to delete all entries where files == theGivenFileName. In sql it would be something like this:
Delete from folder_files where files = XXX
Is there a way to perform this query using criteria-api?
If not, is there a way to perform this query using jpql?
UPDATE:
I think my question was not clear enough:
Since jpql uses entities (and not tables) I cannot just perform the sql written above plus since I'm using #ElementCollection I don't know how to address this variablr or even deal with it. I would like to delete all entries in that collection (in my case, the files set) which holds a given value, from all entities. Is that possible using jpql or (even better) criteria-api?
The Delete FROM clause requires an Entity, so there is no way to delete from an element collection from what I understand.
You can use a native SQL query, or you can map the element collection as a OneToMany to an Entity instead.
You can use the like query just the syntax is slightly changed.
query = em.createQuery("SELECT i FROM Item i WHERE UPPER(i.name) LIKE :keyword ");
query.setParameter("keyword", "%" + keyword.toUpperCase() + "%");
You can read more on following link,
https://forums.oracle.com/forums/thread.jspa?threadID=423742
Updated:
#Noam you can do it: Like in Criteria API
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
Kindly read more on it at following link:
http://ctpconsulting.github.com/query/1.0.0.Alpha3/criteria.html
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
This cannot be done. Via JPQL it does not work because DELETE statement can only be applied to entities. Excerpt from JPA 2.0 specification:
Bulk update and delete operations apply to entities of a single entity
class (together with its subclasses,if any).
...
delete_statement ::= delete_clause [where_clause]
delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]
Also it doesn't work via Criteria API. CriteriaQuery supports only selecting - not updates or removals.
You have to go for native SQL.

JPA Query MONTH/YEAR functions

How can I write a JPA query using MONTH function just like sql query?
#NamedQuery(name="querybymonth", query="select t from table1 t where MONTH(c_Date) = 5")
When I use the above pattern for query, I get an error: unexpected token - MONTH.
If you are using EclipseLink (2.1) you can use the FUNC() function to call any database function that is not defined in the JPA JPQL spec.
i.e.
FUNC('MONTH', c_Date)
In JPA 2.1 (EclipseLink 2.5) the FUNCTION syntax becomes part of the specification (and replaces the EclipseLink-specific FUNC).
If you are using TopLink Essentials, you cannot do this in JPQL, but you can define a TopLink Expression query for it (similar to JPA 2.0 criteria), or use native SQL.
Also if you are using any JPA 2.0 provider and using a Criteria query there is a function() API that can be used to define this.
I want to query YEAR(itemDate) but the function doesn't exit, then i saw the SUBSTRING() function so what i did was
Select q from table where SUBSTRING(itemDate, 1, 4)='2011'
and it works for me! hope it helps!
if you need you a dynamic variable, you can do that too. here :poDate is the year which is deifned in the setParameter();
#NamedQuery(name = "PurchaseOrders.findByYear", query = "SELECT p FROM PurchaseOrders p WHERE SUBSTRING(p.poDate, 1, 4) = :poDate")
Query q = em.createNamedQuery("PurchaseOrders.findByYear");
q.setParameter("poDate", s_year+"");
but if your okay with your solutions, that'll be fine. i just find JPA faster to execute.
The MONTH() function exists in Hibernate HQL but is not a standard JPA function. Maybe your JPA provider has some proprietary equivalent but you didn't mention it. If it doesn't, fall back on native SQL.
I am using Toplink Essentials for the same. Please help, if any function exists in Toplink. Thanks.
To my knowledge, TopLink doesn't have a direct equivalent. So either use a native SQL query or maybe a TopLink Expression query (not sure about this, and not sure this is available in TopLink Essentials).
Following worked for me with hibernate (4.3.9.Final) & JPA 2.1.
#NamedQuery(name = "PartyEntity.findByAID", query = "select distinct psc.party from PartyShortCode psc where (psc.shortCode = :aidNumber or FUNCTION('REPLACE',psc.accountReference,' ','') = :aidNumber) and psc.sourceSystem in :sourceSystem")
if your class holds a date type variable, you can use a query like this:
#Query("select m from Movement m where m.id_movement_type.id=1 and SubString(cast(m.date as text),1,4) = :year")
List<Movement> buysForYear(#Param("year") String year);

Categories