Adding IN clause List to a JPA Query - java

I have built a NamedQuery that looks like this:
#NamedQuery(name = "EventLog.viewDatesInclude",
query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND "
+ "el.timeMark <= :dateTo AND "
+ "el.name IN (:inclList)")
What I want to do is fill in the parameter :inclList with a list of items instead of one item. For example if I have a new List<String>() { "a", "b", "c" } how do I get that in the :inclList parameter? It only lets me codify one string. For example:
setParameter("inclList", "a") // works
setParameter("inclList", "a, b") // does not work
setParameter("inclList", "'a', 'b'") // does not work
setParameter("inclList", list) // throws an exception
I know I could just build a string and build the whole Query from that, but I wanted to avoid the overhead. Is there a better way of doing this?
Related question: if the List is very large, is there any good way of building query like that?

When using IN with a collection-valued parameter you don't need (...):
#NamedQuery(name = "EventLog.viewDatesInclude",
query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND "
+ "el.timeMark <= :dateTo AND "
+ "el.name IN :inclList")

The proper JPA query format would be:
el.name IN :inclList
If you're using an older version of Hibernate as your provider you have to write:
el.name IN (:inclList)
but that is a bug (HHH-5126) (EDIT: which has been resolved by now).

public List<DealInfo> getDealInfos(List<String> dealIds) {
String queryStr = "SELECT NEW com.admin.entity.DealInfo(deal.url, deal.url, deal.url, deal.url, deal.price, deal.value) " + "FROM Deal AS deal where deal.id in :inclList";
TypedQuery<DealInfo> query = em.createQuery(queryStr, DealInfo.class);
query.setParameter("inclList", dealIds);
return query.getResultList();
}
Works for me with JPA 2, Jboss 7.0.2

You must convert to List as shown below:
String[] valores = hierarquia.split(".");
List<String> lista = Arrays.asList(valores);
String jpqlQuery = "SELECT a " +
"FROM AcessoScr a " +
"WHERE a.scr IN :param ";
Query query = getEntityManager().createQuery(jpqlQuery, AcessoScr.class);
query.setParameter("param", lista);
List<AcessoScr> acessos = query.getResultList();

Related

How can you set a list as a query paramter? [duplicate]

I have built a NamedQuery that looks like this:
#NamedQuery(name = "EventLog.viewDatesInclude",
query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND "
+ "el.timeMark <= :dateTo AND "
+ "el.name IN (:inclList)")
What I want to do is fill in the parameter :inclList with a list of items instead of one item. For example if I have a new List<String>() { "a", "b", "c" } how do I get that in the :inclList parameter? It only lets me codify one string. For example:
setParameter("inclList", "a") // works
setParameter("inclList", "a, b") // does not work
setParameter("inclList", "'a', 'b'") // does not work
setParameter("inclList", list) // throws an exception
I know I could just build a string and build the whole Query from that, but I wanted to avoid the overhead. Is there a better way of doing this?
Related question: if the List is very large, is there any good way of building query like that?
When using IN with a collection-valued parameter you don't need (...):
#NamedQuery(name = "EventLog.viewDatesInclude",
query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND "
+ "el.timeMark <= :dateTo AND "
+ "el.name IN :inclList")
The proper JPA query format would be:
el.name IN :inclList
If you're using an older version of Hibernate as your provider you have to write:
el.name IN (:inclList)
but that is a bug (HHH-5126) (EDIT: which has been resolved by now).
public List<DealInfo> getDealInfos(List<String> dealIds) {
String queryStr = "SELECT NEW com.admin.entity.DealInfo(deal.url, deal.url, deal.url, deal.url, deal.price, deal.value) " + "FROM Deal AS deal where deal.id in :inclList";
TypedQuery<DealInfo> query = em.createQuery(queryStr, DealInfo.class);
query.setParameter("inclList", dealIds);
return query.getResultList();
}
Works for me with JPA 2, Jboss 7.0.2
You must convert to List as shown below:
String[] valores = hierarquia.split(".");
List<String> lista = Arrays.asList(valores);
String jpqlQuery = "SELECT a " +
"FROM AcessoScr a " +
"WHERE a.scr IN :param ";
Query query = getEntityManager().createQuery(jpqlQuery, AcessoScr.class);
query.setParameter("param", lista);
List<AcessoScr> acessos = query.getResultList();

Hibernate createNativeQuery - get more than one Entity

I am using following code to execute native SQL query with hibernate:
Query zonesQuery = session.createNativeQuery(
"Select * \n" +
"FROM dbo.Structure AS S\n" +
"JOIN dbo.StructureLocationType AS SLT ON SLT.StructureId = S.Id\n" +
"WHERE SLT.LocationTypeId = :lc").addEntity(StructureEntity.class);
zonesQuery.setParameter("lc", locationTypeID);
List<StructureEntity> zones = zonesQuery.list();
So it works and it gets me list of StructureEntity
now, because my sql query "join" from StructureLocationType table, is there possibility to get whole StructureLocationType row as well, still using single query?
Thank you.
It can be achieved with the following (notice curly braces in SQL and entities aliases):
Query query = session
.createNativeQuery(
"SELECT {S.*}, {SLT.*} " +
"FROM dbo.Structure AS S " +
"JOIN dbo.StructureLocationType AS SLT ON SLT.StructureId = S.Id " +
"WHERE SLT.LocationTypeId = :lc")
.unwrap(SQLQuery.class)
.addEntity("S", StructureEntity.class)
.addEntity("SLT", StructureLocationTypeEntity.class)
.setParameter("lc", locationTypeID);
List<Pair<StructureEntity, StructureLocationTypeEntity>> result = ((List<Object[]>) query.list())
.stream()
.map(p -> Pair.of((StructureEntity) p[0], (StructureLocationTypeEntity) p[1]))
.collect(Collectors.toList());
You can't get multiple Objects from one query.
But you could either select which columns you want and then iterate the returned Object array:
The query:
SELECT s.id, s.someColumn, slt.id, slt.structureId
FROM dbo.Structure AS s
JOIN dbo.StructureLocationType AS slt on slt.structureId = s.id
WHERE slt.locationTypeId = :lc
Then iterate over the Object array:
List<Object[]> result = query.getResultList();
Or you could create a view on your database and map it to a java entity using the Table annotation like it was a normal table:
#Entity
#Table(name = "STRUCTURE_LOCATION_TYPE_VIEW")
public class StructureAndLocationType {
// ...
}
I thought there is a way to map from a query to an Object without creating a DB view but couldn't find it right now.

Wrong BigInteger result using hibernate native query

I'm using Hibernate4 + PostgresSql.
I need to get a list of ids from my DB without getting a whole object.
I use a native query (because it's hierarchical) and it looks like:
String s = hierachical_part_skipped +"select id " +
"from search_hierarchy " +
"order by id";
Query q = getEntityManager().createNativeQuery(s);
List<Long> resList = new ArrayList<>();
List<BigInteger> biglist = q.getResultList();
for (Object id : biglist) {
System.out.print(id+",");
resList.add(id.longValue());
}
Well, 1 time out of three my bigList is filled with wrong values!
I have
10,20,30,40,50,60,70,80,90,100 ... 27350
instead of
1, 2... 2735
(a zero is added to each value).
Native query executed manually not through Hibernate returns correct values.
I've tried retrieving result as List of Object, but the result was the same
I have found a sufficient workaround
s.append("select id \\:\\:numeric " + //that's a hack
"from search_department " +
"order by id");
Query q = getEntityManager().createNativeQuery(s);
List<Long> resList = new ArrayList<>();
List<BigDecimal> biglist = q.getResultList();
for (BigDecimal id : biglist) {
System.out.print(id + ",");
resList.add(id.longValue());
}
Still, I'm wondering why BigInteger works incorrectly

Need a help to create hibernate query

need a help to create hibernate query that table is jdwCustomerTlrdRef and it should take all the operation_spec = customer name. the method should return sysId.
Here is the code to review. Please help me i am new to this hibernate query.
public getCustomerTlrdRef(BigDecimal sysId) {
System.out.println("---- getAllCustomerTlrdRef " );
String query = "from JdwCustomerTlrdRef as jdwCustomerTlrdRef where jdwCustomerTlrdRef.operation_spec= '+customer_name+'";
Query q = getSessionFactory().getCurrentSession().createQuery(query);
List<JdwCustomerTlrdRef> customerTlrdRefSysId = q.list();
System.out.println(" List size: " + customerTlrdRefSysId.size());
return customerTlrdRefSysId;
}
This should work.
String query = "from JdwCustomerTlrdRef jdwCustomerTlrdRef where jdwCustomerTlrdRef.operation_spec= '+ customer_name +'";
Otherwise if you want to pass the parameter later in your code then do it this way.
String query = "FROM JdwCustomerTlrdRef jdwCustomerTlrdRef WHERE jdwCustomerTlrdRef.operation_spec = :customer_name"
then in your code you can pass the parameter this way.
query.setParameter("customer_name", theCustomerNameParameter);

Error: Cannot create TypedQuery for query with more than one return

I try to do the function searchBook with java and jpa. I have 2 classes which are Media and Book. Book extends Media. And I keep the data in the different table. I try to select the data from the query below:
TypedQuery<Media> query = em.createQuery(
"SELECT m.title, b.isbn, b.authors"
+ " FROM Book b, Media m" + " WHERE b.isbn = :isbn"
+ " OR lower(m.title) LIKE :title"
+ " OR b.authors LIKE :authors", Media.class);
query.setParameter("isbn", book.getisbn());
query.setParameter("title", "%" + book.getTitle().toLowerCase()
+ "%");
query.setParameter("authors", "%" + book.getAuthors() + "%");
bookList = query.getResultList();
But I got the error:
java.lang.IllegalArgumentException: Cannot create TypedQuery for query
with more than one return
This is the first time I use JPA. I can't find the the mistake.
As a workaround, to get entity composed by other entity attributes, you can create it within query, providing constructor for it.
Query :
TypedQuery<Media> query = em.createQuery("SELECT NEW package_name.Media(m.title, b.isbn, b.authors)"
+ " FROM Book b, Media m"
+ " WHERE b.isbn = :isbn"
+ " OR lower(m.title) LIKE :title"
+ " OR b.authors LIKE :authors", Media.class);
Entity :
public Media(String title, int isbn, String author){
//-- Setting appropriate values
}
I have provided sample, change the datatypes of the constructor accordingly.
Without goind into details about how Media and Book should be modeled, I will at least explain why you get this exception.
You're doing:
em.createQuery(someJPQL, Media.class);
This means: create a query using someJPQL, and this query will return instances of the Media entity.
But your JPQL is:
SELECT m.title, b.isbn, b.authors ...
So the query does not return entities of type Media. It returns three fields, from two different entities. There is no way your JPA engine could magically create instances of Media from these 3 columns. A query would return instances of Media if it looked like this:
select m from Media m ...
If you still want to use TypedQuery you can change the result type to Object[].
List<Object[]> results = entityManager
.createQuery("SELECT m.title, b.isbn, b.authors ...", Object[].class)
.getResultList();
Each Object[] in the List represents a row of data. It contains the selected values for that row in the order in which they were selected in the query. Element 0 is the title, element 1 is the ISBN, and element 2 is the authors. You'll likely need to cast those values if you want to use them in a meaningful way. Since the field values come from two different tables, you could store them in some kind of container object.
List<MediaContainer> mediaList = new ArrayList<>();
for (Object[] row : results) {
MediaContainer container = new MediaContainer();
container.setTitle((String) row[0]);
container.setIsbn((int) row[1]);
container.setAuthors((String) row[2]);
mediaList.add(container);
}
#WebUser instead of doing
List<EntityIDKey> companies =
getEntityManager().createQuery(sql, EntityIDKey.class).getResultList();
Try this :
List<EntityIDKey> companies =
(List<EntityIDKey>)getEntityManager().createQuery(sql).getResultList();
works for me.
if your are using Hibernate version < 4, you can meet this bug.
I go same problem with v3.5. Finally i had to use simple Query and cast each parameter manually
see other comments here : https://groups.google.com/forum/#!topic/axonframework/eUd1d4rotMY
I... remove
Media.class
of
createQuery
because you return more Entities in this source "SELECT m.title, b.isbn, b.authors"
Ex.:
TypedQuery<Media> query = em.createQuery(
"SELECT m.title, b.isbn, b.authors"
+ " FROM Book b, Media m" + " WHERE b.isbn = :isbn"
+ " OR lower(m.title) LIKE :title"
+ " OR b.authors LIKE :authors");
You can resolve the issue by doing this kind of query:
em.createQuery( "SELECT m"
+ " FROM Book b, Media m" + " WHERE b.isbn = :isbn"
+ " OR lower(m.title) LIKE :title"
+ " OR b.authors LIKE :authors", Media.class);
but this works only if you need fields only from one of the requested tables

Categories