Wrong BigInteger result using hibernate native query - java

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

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();

Convert to DTO from join selection

I have these two tables
And I am using this query to get the results
#Query(value = "SELECT bet.bet, match.name, match.week FROM bet INNER JOIN match ON match.id=bet.match_id WHERE match.week = ?1", nativeQuery = true)
List<Object[]> customQuery(Long week);
So far this is the only way I could retrieve the results and actually use them later.
To use them I am using this code currently
List<Object[]> bets = gr.customQuery(2l);
for (Object[] object : bets) {
int bet = (BigInteger) object[0];
String name = (String) object[1];
int week = (BigInteger) object[2];
System.out.println(bet + " " + name + " " + week);
}
But using it that way seems odd to me. Is there a better way to directly map the result to a DTO or something...
There are some options. The most straighforward way would be to define a projection Interface, like:
public interface BetDTO {
Long getBet();
String getName();
Integer getWeek();
}
With that you could change your query return type to:
List<BetDTO> customQuery(Integer week);
The rest would then be using getters.

How to query a database table for a list of record with only two data objects

My database table looks like:
ID ACCESSID ENTITYGUID NAME NAMEID OWNERGUID TIMECREATED VALUEID VALUETYPE
I want to only retrieve a list with two fields, name AND valueId, not the whole record. I'm attempting this as follows:
via projections:
public void getAllEntityMetadata(int GUID) {
Criteria c = session.createCriteria(RevMetadata.class)
.add(Restrictions.eq("entityGUID", GUID))
.setProjection(Projections.property("name"))
.setProjection(Projections.property("nameId"));
List<RevMetadata> m = (List<RevMetadata>) (RevMetadata) c.list();
for (RevMetadata item : m) {
System.out.println("-> All entity metadata for GUID: " + item.getName() + " : " + item.getValueId());
}
}
I get the error:
Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to wakiliproject.Persistence.RevMetadata
at wakiliproject.Persistence.PersistRevMetadata.getAllEntityMetadata(PersistRevMetadata.java:112)
at wakiliproject.HomeController.showMetastring(HomeController.java:492)
... 40 more
Via query by example, I'm only getting the output below but no data. No error gets called:
public void getAllEntityMetadataEg(int GUID) {
RevMetadata m = new RevMetadata();
m.setEntityGUID(GUID);
Example e = Example.create(m);
Criteria c = session.createCriteria(RevMetadata.class).add(e);
for (Iterator it = c.list().iterator(); it.hasNext();) {
RevMetadata item = (RevMetadata) it.next();
System.out.println("-> All entity metadata for GUID: " + item.getName() + " : " + item.getValueId());
}
}
The output:
Hibernate: select this_.id as id1_4_0_, this_.accessId as accessId2_4_0_, this_.entityGUID as entityGU3_4_0_, this_.name as name4_4_0_, this_.nameId as nameId5_4_0_, this_.ownerGUID as ownerGUI6_4_0_, this_.timeCreated as timeCrea7_4_0_, this_.valueId as valueId8_4_0_, this_.valueType as valueTyp9_4_0_ from METADATA this_ where (this_.accessId=? and this_.entityGUID=? and this_.nameId=? and this_.ownerGUID=? and this_.timeCreated=? and this_.valueId=?)
None of the approaches work. Please help me make it work so that I can get a list with two data objects of name and nameId
Update:
The database table entity class:
public class RevMetadata implements Serializable {
private String name;
private int valueId;
}
If only some specified columns will be retrieved, the result will be List<Object[]>.
In your case, Object[] will be populated with name value => index 0 and nameId => index 1. Need to cast it to target value's type.
Criteria criteria = session.createCriteria(RevMetadata.class);
criteria.add(Restrictions.eq("entityGUID", GUID));
criteria.setProjection(Projections.projectionList()
.add(Projections.property("name"))
.add(Projections.property("nameId")));
List<Object[]> criteriaResult = criteria.list();
List<RevMetadata> results = new ArrayList<RevMetadata>();
//then get result into the class properties
for (Object[] object : criteriaResult) {
//cast to target value type
String name = (String)object[0];
int nameId = ((Integer)object[1]).intValue();
RevMetadata result = new RevMetadata();
result.setName(name);
result.setValueId(nameId);
results.add(result);
}
//now results of List<RevMetadata> is ready
The projections needs to be added to projectList if you want to get multiple columns:
Projections.projectionList()
.add(Projections.property("name"))
.add(Projections.property("valueId"))
Also the c.list() returns a List and this list contains the fields added to your projection list so it contains an object array with first field as your name property and second field as your valueId property. So your c.list() should be like:
List<Object[]> rows = (List<Object[]>) c.list();
So here are the changes that works:
Criteria c = session.createCriteria(RevMetadata.class)
.add(Restrictions.eq("entityGUID", GUID));
c.setProjection(Projections.projectionList()
.add(Projections.property("name"))
.add(Projections.property("valueId")));
List<Object[]> rows = (List<Object[]>) c.list();
System.out.println(rows);
for (Object[] row : rows) {
System.out.println(row[0] + " and " + row[1]);
}
It seems that the Problem is the double casting
(List<RevMetadata>) (RevMetadata) c.list();
Try to remove the cast
(RevMetadata)
List m = c.list();
for(Iterator it = c.iterator(); it.hasNext()) {
Object[] row = (Object[]) it.next();
System.out.println("-> All entity metadata for GUID: " + row[0] + " : " +row[1]);
}

HQL - two same queries - difference in object types

Why I have to use Object[] to print the list if I select specific columns:
Session session = DaoSF.getSessionFactory().openSession();
List<Object[]> list = new ArrayList<Object[]>(); /* Object[] */
Query criteria = session.createQuery(
"select test.col1, test.col2, test.col3
"from Test test " +
"group by test.col1, test.col2, test.col3");
list = criteria.list();
for (Object[] item : list)
{
System.out.println(item[1] + ", " + item[2] + ", " + item[3]);
}
And why is it possible to iterate the same select (select * -- not the specific columns) using original Test object?
List<Test> list = new ArrayList<Test>(); /* Test */
Query criteria = session.createQuery(
"from Test test " +
"group by test.col1, test.col2, test.col3");
list = criteria.list();
for (Test item : list)
{
System.out.println(item.getCol1 + ", " + item.getCol2 + ", " + item.getCol3);
}
Is it possible to "convert" Object[] to Test object?
Try this approach; first create a constructor in your Test class:
public Test(Col1Type col1, Col2Type2 col2, Col3Type col3) {
this.col1 = col1;
this.col2 = col2;
this.col3 = col3;
}
Now in the query, you can say:
select new Test(t.col1, t.col2, t.col3)
from Test t
This will give Hibernate a so-called row-mapper constructor out of which it can construct the objects of Test. Then you will have a List<Test> from query.list(). This approach has a catch that you should provide different constructors beside the default one for different possible queries.
in your first query , you return a row (like a list) , consisting of several attributes of a "test" object that you have selected.
it is not "test" object , so you cannot iterate such way.
in your second query , you return the "test" object : a list of "Test" objects , so you can iterate as "test" object.

Adding IN clause List to a JPA Query

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();

Categories