Execute dynamic query with Spring Data JPA - java

#Query(value = "SELECT * FROM H4 WHERE 1")
List getResult();
Instead of the query "SELECT * FROM H4 WHERE 1" I want to put a String variable containing query generated elsewhere.

#Query, like any other annotation, uses a compile time constant to define attributes. You can't define it's value in runtime unless you plan to hack the Spring Data JPA framework.
You should use either Specifications with criteria, Query by example or JPQL to define and execute your dynamic query.

Create constants and set the value as below.
#Query(value = ApplicationConstantClass.QUERY_STRING_CONSTANT)
List getResult();
or Use EntityManager or SessionFactory of hibernate to execute dynamically generated query.

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.

Language injection in intellij with #Query

Using intellij idea 2016-3.4, is it possible to inject a language based on a parameter? Consider this
#Query(nativeQuery = true, value = "select * from Foo")
List<Foo> nativeQuery();
#Query(value = "select a from Foo a")
List<Foo> hqlQuery();
The first example is a native mySql query, so I'd like to inject mySql dialect, while the second one is a hql query, where I would like to inject the hibernate query language.
Right now, if I inject a language in one of the both query strings, both change to that language injection.
Can I make idea understand the nativeQuery parameter in the #Query annotation?
Yes it's possible.
You can't to do it over Language Injection window.
But you can use language injection comments or #Language annotation. Below I inject MySQL and HTML in the same annotation using comments:
To remove comment hit Alt+Enter (OS X ⌥+Enter) and choose Un-inject Language/Reference.

How to create native queries in Spring?

I have a spring application that should connect to an existing database and just query an entity for existence based on some attributes.
I don't want to create a #Entity class for this. But I still want to use the spring managed EntityManager etc.
When using Spring, what is the best approach to just query a select for that entity? Using em.createNamedQuery(QUERY); with String QUERY = "SELECT count(*) from my_table where username =: username AND email := email)";?
Answers from #predrag-maric and #pL4Gu33 are both correct but if you use JPA in your project (for example, Hibernate) you might consider using #NamedNativeQuery annotation as well.
More about named native queries.
simple example of native query
#PersistenceContext
EntityManager em;
public String test(Integer id)
{
Query query = em.createNativeQuery("SELECT name FROM Accounts where id=?");
query.setParameter(1,id);
return query.getSingleResult();
}
You can use this method from entitymanager. http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#createNativeQuery%28java.lang.String%29
Use em.createNativeQuery(QUERY). Also, you'll have to use positional parameters (?1) instead of named parameters (:email), because only positional parameters are supported by JPA in native queries.

Spring Data - Why it's not possible to have paging with native query

Let's say we have an entity called MyEntity. It is possible to query pageable results using #Query and with named queries, e.g.
#Query(value = "select e from MyEntity e where e.enabled = true")
Page<MyEntity> findAllEnabled(Pageable pageable);
However, it is not possible to achieve the same with native query, so this
#Query(value = "select * from my_entity where enabled = true", nativeQuery = true)
Page<MyEntity> findAllEnabled(Pageable pageable);
won't work.
What are the reasons behind this? Is it possible to make Pageable working with native queries?
I don't know if this is still relevant to you: At least in Spring Data JPA 1.9.4 you can specify two queries.
Given a repository:
interface FoobarEntityRepository extends JpaRepository<FoobarEntity, Integer> {
Page findFoobarsSpecialQuery(String someParameter, final Pageable pageable);
}
You can add 2 native queries to your entity, one for the query itself and one for the count statement:
#Entity
#SqlResultSetMappings({
#SqlResultSetMapping(name = "SqlResultSetMapping.count", columns = #ColumnResult(name = "cnt"))
})
#NamedNativeQueries({
#NamedNativeQuery(
name = "FoobarEntity.findFoobarsSpecialQuery",
resultClass = DailyPictureEntity.class,
query = "Select * from foobars f where someValue = :someParameter "
),
#NamedNativeQuery(
name = "FoobarEntity.findFoobarsSpecialQuery.count",
resultSetMapping = "SqlResultSetMapping.count",
query = "Select count(*) as cnt from foobars f where someValue = :someParameter "
)
})
FoobarEntity {
}
The trick is to specify the count query with the suffix .count. This works also with the Spring Data #Query annotation.
Notice that you need a SQL result set mapping for the count query, though.
This works actually pretty nice.
This is description, given in spring data jpa documentation (http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/)
Native queriesThe #Query annotation allows to execute native queries
by setting the nativeQuery flag to true. Note, that we currently don’t
support execution of pagination or dynamic sorting for native queries
as we’d have to manipulate the actual query declared and we cannot do
this reliably for native SQL.
JPQL abstracts SQL implementation and it's providers specifics, and makes it responsibility of ORM framework to generate correct SQL.
So by using Pagination in JPQL form, Spring just needs to generate correct JPQL, and it will be interpreted on ORM level to correct SQL.
While doing so with SQL, would imply that Spring knows how to generated correct SQL for the vast majorities of RDBMS, duplicating ORM functionality, which is too much overhead.
There is a way to use Pageable with native queries with the SpEL capacity of Spring data, it is mention here.
You can find an example in this repository.
/**
* #see DATAJPA-564
*/
#Query(
value = "select * from (select rownum() as RN, u.* from SD_User u) where RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize}",
countQuery = "select count(u.id) from SD_User u", nativeQuery = true)
Page<User> findUsersInNativeQueryWithPagination(Pageable pageable);
The sort functionnality will not work properly if there is a subquery in the fromclause or your native query and you wish to apply a dynamic sort on it. The way it can be done is to move the subquery in the where clause.
Spring data will append to the end of your request " order by " if there is a Sort object in the Pageable. (with Spring data 1.10.3)
A better way is to convert the native query in jpql if possible.

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.

Categories