Hibernate result list cast to get rows - java

Hello I had problem with iterate Hibernate ResultList
I had followed query that I got from external class:
queryContent = "select distinct c.identity, c.number, c.status, ctr.name, aab.paymentConditions.currency from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
And I must sum whole aab.paymentConditions.currency, check numbers of statutes and names.
I want to do this by iterate list of results:
Query q = session.createQuery(queryContent);
List result = q.list();
Long wholeCurrency, numberOfStatutes;
for(Object res : result){
//wholeCurrency += res.getColumnName?
}
My question is how to cast res Object to have possibility to get concrete column values? I had read about create map inside hibernate query but I don't know it is good practice to modyfied query string by adding
"new map(" prefix and then ")"
before from sql statement
Solution:
After All I decided to use map in my query. I modified my external query by adding hibernate map statement by replacing select by 'select new map(' and from by ') from'.
Additional thing is to add 'as' statement with name of key because without them column keys are integer.
So after all my query looks like follow:
"select new map( distinct c.identity, c.number, c.status as status, ctr.name as name, aab.paymentConditions.currency as currency ) from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
That was the most siutable solution for me, I tried with 'NEW com.example.MyClass' as Kostja suggested but in my case I didn't have control for incoming query so I can not rely on pernament constructor.
new List( select...
Is also interest but it also didn't tell me on with position I have my field that give me information.

If I understand correctly, you want to have a typed representation of your result without it being an entity itself. For this, you can use constructor queries:
"SELECT NEW com.example.MyClass( e.name, e.data) FROM Entity e"
MyClass has to have a matching constructor. Full qualification (com.example) is not mandatory AFAIK.
If you are using this query often, creating a view in the DB may be a good idea. You can map a view to an entity just as if it were a regular table, but please note that you cannot store changes to you data over a mapped view.
EDIT: Turns out, mapping to an unspecified Map is alright with Hibernate:
select new map( mother as mother, offspr as offspr, mate as mate )

As per http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-select-clause
you can use
queryContent = "select new list(distinct c.identity, c.number, c.status, ctr.name, aab.paymentConditions.currency) from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
And you get List<List> as result.

Related

Apache Ignite cache "IN" clause not working

What I want to do is
final String query = "select userName from users where userId in
(?) and isActive = 1";
SqlFieldsQuery sql = new SqlFieldsQuery(query);
List<Long> userIds = new ArrayList<Long>();
userIds.add(140l);
userIds.add(245l);
sql.setArgs(userIds.toArray());
List<List<?>> rsList = usersCache.query(sql).getAll();
. It is not giving the desired result. It is returning only one result
instead of two.
Please suggest
It's impossible to pass an array as an argument for in. You can rewrite your query to use a join instead. It will look as follows:
select u.userName from users u
join table (userId bigint=?) t on u.userId=t.userId
where u.isActive=1
Another thing you should take into account is that SqlFieldsQuery.setArgs(...) takes a vararg as an argument. So, to prevent your array from being unfolded, you should add a cast to Object:
sql.setArgs((Object)userIds.toArray());

Dynamic search using sql queries

I'm implementing dynamic search within my application, I have the following options to build a query.
String concatenation from the user input
Use multiple Queries, and pull the right query based on the user input
Use one query, use wild cards for the inputs not given by the user.
eg:
select * from A,B where a.id like nvl( {input}, '%')
and a.id = b.aid
and b.value like nvl({input2},'%');
Because id is a primary key I get the following error in the oracle when tried.
Firstly, for wildcard search you need to use the LIKE predicate, not =. Secondly, you can't use the LIKE predicate for numeric data, obviously. What you can do is this:
select * from A,B where ( a.id = {input} or {input} is null )...
A simple solution could be:
StringBuffer sqlSB = new StringBuffer("select * from A,B where a.id = b.aid ");
if(input!=null&&!input.equals("")){
sqlSB.append(" and a.id = ").append(input);
}
if(input2!=null&&!input2.equals("")){
sqlSB.append(" and b.value = '").append(input2).append("' ");
}

How to flatten the results of a Hibernate query

Say I executed a theoretical HQL query like FROM Customer. And in Customer is a getOrders() getter returning a ManyToOne collection of Order objects. This executes a SQL statement selecting from Customer with a left join to Order.
Through the object model, I can programmaticly iterate over Customers and then iterate over Orders.
However, I want to convert the hierarchical object model to a flat tabular result of the left join so that the results would look much like that of this SQL query:
SELECT *
FROM Customer
LEFT JOIN Order on Customer.customerId = Order.customerId
Sample result:
Customer.customerId ... Order.orderId Order.customerId ...
1 200 1
2 201 2
2 202 2
3 NULL NULL
Is there an easy way to do this with Hibernate?
Depends what you want at the "scalar" level which you control through using an explicitl select clause.
select c, o
from Customer c left join c.orders o
returns you List of (Customer, Order) tuples. Or:
select c.id, c.name, o.id, ...
from Customer c left join c.orders o
which returns you a scalar projection of the atomic pieces.
In both cases you get back a List. You can use "dynamic instantiation" in both cases (though really its more useful in the second case imho):
select new CustomerOrderSummary( c.id, c.name, o.id, ... )
from Customer c left join c.orders o
where CustomerOrderSummary is just a plain class with matching constructor.
Possible you can do this via expressing of result set. http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/query_native.html
From the example:
#SqlResultSetMapping(name="GetNightAndArea", entities={
#EntityResult(name="org.hibernate.test.annotations.query.Night", fields = {
#FieldResult(name="id", column="nid"),
#FieldResult(name="duration", column="night_duration"),
#FieldResult(name="date", column="night_date"),
#FieldResult(name="area", column="area_id")
}),
#EntityResult(name="org.hibernate.test.annotations.query.Area", fields = {
#FieldResult(name="id", column="aid"),
#FieldResult(name="name", column="name")
})
})
I think you can try retrieving results in Object[] e.g. below:
EntityManager entityManager = EntityManager.getEntityManager();
Query query= entityManager.createQuery("select cust, ord from Customer cust left outer join cust.orders ord where cust.customerId = :customerId");
tradeQuery.setParameter("customerId", aCustomerId);
List<Object[]> resultList = (List<Object[]>)query.getResultList();
The retrieved resultsList will be list of Object array containing Customer and Order objects in flat.
if(!resultList.isEmpty()){
Iterator<Object[]> iter = resultList.iterator();
while(iter.hasNext()){
Object[] resultObj = (Object[])iter.next();
Customer customer= (Customer )resultObj[0];
Order order = (Order)resultObj[1];
}
}
Hope this helps!

How to run an aggregate function like SUM on two columns in JPA and display their results?

I am new to JPA. So my question should be so simple to some.
Below is the Simple Query in SQL which i would like to convert to JPA. I already have an entity class called TimeEnt.
SELECT
SUM(TimeEntryActualHours) as UnBilledHrs,
SUM (TimeEntryAmount) as UnbilledAmount
FROM TimeEnt WHERE MatterID = 200
The JPA Query Language does support aggregates functions in the SELECT clause like AVG, COUNT, MAX, MIN, SUM and does support multiple select_expressions in the SELECT clause, in which case the result is a List of Object array (Object[]). From the JPA specification:
4.8.1 Result Type of the SELECT Clause
...
The result type of the SELECT
clause is defined by the the result
types of the select_expressions
contained in it. When multiple
select_expressions are used in the
SELECT clause, the result of the query
is of type Object[], and the
elements in this result correspond in
order to the order of their
specification in the SELECT clause
and in type to the result types of
each of the select_expressions.
In other words, the kind of query you mentioned in a comment (and since you didn't provide your entity, I'll base my answer on your example) is supported, no problem. Here is a code sample:
String qlString = "SELECT AVG(x.price), SUM(x.stocks) FROM Magazine x WHERE ...";
Query q = em.createQuery(qlString);
Object[] results = (Object[]) q.getSingleResult();
for (Object object : results) {
System.out.println(object);
}
References
JPA 1.0 Specification
4.8.1 Result Type of the SELECT Clause
4.8.4 Aggregate Functions in the SELECT Clause
Lets think we have entity called Product:
final Query sumQuery = entityManager
.createQuery("SELECT SUM(p.price), SUM(p.sale) FROM Product p WHERE p.item=:ITEM AND ....");
sumQuery.setParameter("ITEM","t1");
final Object result= sumQuery.getSingleResult(); // Return an array Object with 2 elements, 1st is sum(price) and 2nd is sum(sale).
//If you have multiple rows;
final Query sumQuery = entityManager
.createQuery("SELECT SUM(p.price), SUM(p.sale) FROM Product p WHERE p.item in (" + itemlist
+ ") AND ....");
// Return a list of arrays, where each array correspond to 1 item (row) in resultset.
final List<IEniqDBEntity> sumEntityList = sumQuery.getResultList();
Take a look at the EJB Query Language specification.
The idiom is very similiar to standard SQL
EntityManager em = ...
Query q = em.createQuery ("SELECT AVG(x.price) FROM Magazine x");
Number result = (Number) q.getSingleResult ();
Regards,

Hibernate "IN" clause as ALL instead of ANY

I'd like to start by apologizing for my unfamiliarity with Hibernate. I'm only recently getting into it and am far from an expert.
I have three tables: Contract, Products, and a link table between them to define a many to many relationship.
I'm trying to write an HQL query to return all contracts that contain a range of products. Unfortunately, the IN syntax works like an Any instead of an All. So if I want all contracts that have ProductA, ProductB, and ProductC, the IN keyword will return me contracts that have any individual one of those products, instead of contracts that have all of them.
How should I structure my HQL query?
Why are you expecting IN to behave like a AND? To my knowledge, IN is a kind of OR, not a AND. IN might thus not be what you're looking for. Have a look at Hibernate's Expressions and especially:
HQL functions that take collection-valued path expressions: size(), minelement(), maxelement(), minindex(), maxindex(), along with the special elements() and indices functions that can be quantified using some, all, exists, any, in.
[...]
The SQL functions any, some, all, exists, in are supported when passed the element or index set of a collection (elements and indices functions) or the result of a subquery (see below):
[...]
from Show show where 'fizard' in indices(show.acts)
For more than 2000 ids at in clause use a subquery like [from group where groupid in(select id from elemtable)]
Otherwise use criteria to overcome the stackoverflow error.
Example:
Session session = getHibernateTemplate().getSessionFactory().openSession();
Criteria criteriaEaquals = session.createCriteria(Elements.class);
criteriaEaquals.add(Restrictions.in("elementId", elemIds));
criteriaEaquals.setProjection(Projections.distinct(Projections.property("type")));
List list = criteriaEaquals.list();
session.close();
System.out.println("typelistis--->"+list.toString());
return list;
You can use group by / having:
select c
from Contract c join c.products p
where p.name in ('A', 'B', 'C')
group by c.id, // list ALL Contract properties
having count(*) = 3
Alternatively you can use a subquery to avoid listing all properties in group by:
from Contract c where c.id in (
select c.id
from Contract c join c.products p
where p.name in ('A', 'B', 'C')
group by c.id
having count(*) = 3
)
Obviously "3" will have to be replaced with the actual number of product names you supply in in clause.
In the blog I went over such hibernate queries, take a look at example #4.
Here is a snapshot (replace Articles with Contracts and Tags with Products):
String[] tags = {"Java", "Hibernate"};
String hql = "select a from Article a " +
"join a.tags t " +
"where t.name in (:tags) " +
"and a.id in (" +
"select a2.id " +
"from Article a2 " +
"join a2.tags t2 " +
"group by a2 " +
"having count(t2)=:tag_count) " +
"group by a " +
"having count(t)=:tag_count";
Query query = session.createQuery(hql);
query.setParameterList("tags", tags);
query.setInteger("tag_count", tags.length);
List<Article> articles = query.list();

Categories

Resources