JOOQ - convert result into Pojo - java

I have seen that JOOQ can automatically return a POJO when we use .selectFrom(TABLE) or .fetchInto(POJO.class);
But is it possible to convert the result of a complex query into multiple POJO ?
Example :
This query will return an array of all columns into tables Support and Box. It is possible to convert them into a Support and Box Pojo ?
Result<Record> results = query.select()
.from(BOX)
.join(SUPPORT)
.on(SUPPORT.ID.equal(BOX.SUPPORT_ID))
.where(SUPPORT.ID.equal("XXXX"))
.orderBy(BOX.ID)
.fetch();
I have tested the method .intoGroups(SUPPORT.ID, Box.class) , it works fine. But I doesn't have the support object.

Instantiate to SelectSeekStep1
With aliases it's more convenient:
Box b = BOX.as("b");
Support s = SUPPORT.as("s");
SelectSeekStep1<Integer, Integer> sql = query.select(b.ID, s.ID /* other columns */)
.from(b)
.join(s)
.on(s.ID.eq(b.SUPPORT_ID))
.where(s.ID.eq("XXXX"))
.orderBy(b.ID)
;
Then just fetch what/as you need:
List<BoxRecord> boxes = sql.fetchInto(BOX);
SupportRecord support = sql.limit(1).fetchOneInto(SUPPORT);

For future readers, if you want to achieve the same behaviour with insert methods you should use:
insertInto(BOX)
.set(BOX.COLUMN1, UInteger.valueOf(1))
.set(BOX.COLUMN2, "test")
.returning()
.fetchOne()
.into(<POJO_class>.class);

Related

Unable to map JSON field from postgres DB to POJO class

I have below code in place where I am trying to get only 1 column (JSON type) from postgres DB and map it to a POJO class. But, in the result I am getting correct count but with null values only, even though data is present. Any Help/Suggestion is appreciated.
POJO Class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class EmployeePayload {
private String empName;
private String empID;
//getters and setters
}
Query Execution Code ::
String query = "SELECT emp_payload FROM EmpDetails";
ResultSetHandler<List<EmployeePayload>> employeePayload = new BeanListHandler<EmployeePayload>(EmployeePayload.class);
List<EmployeePayload> resultList = runner.query(dbConnection, query, employeePayload);
log.info(":: resultList is :: " + resultList);
Data in DB ::
"{""empName"":""james"",""empID"":""008""}",
"{""empName"":""bond"",""empID"":""007""}"
Result in Log ::
resultList is :: [EmployeePayload{empName='null', empID='null'}, EmployeePayload{empName='null', empID='null'}]
The BeanListHandler comes from apache dbutils (docs)
By looking at the docs / source, it's implemented by mapping single columns to single properties of the Bean. You are essentially trying to map a single column to multiple properties which does not work. Now there are two ways to go about this:
Writing your own RowProcessor
Rewriting the query to return multiple columns.
In this situation I would favor the second solution for it's simplicity as postgres has this functionality built-in for its json field types.
Your query could look like this:
String query = "SELECT emp_payload->'empName' AS empName, emp_payload->'empID' AS empID FROM EmpDetails";
(The AS ... might not be necessary but I don't know how psql generates the column names for extracted json values).
If you would execute this query directly in postgres, you would get a result set with column names empName and empID which is exactly what the BeanProcessor (the default processor for BeanListHandler) expects.

Hibernate - Query columns map into object, the rest of the columns set to null or default value

Basically if we want to query specific columns, we do this:
Query query =
session.createQuery("SELECT tr.review from TravelReview as tr");
List<String> reviews = query.list();
And if we want the original object (TravelReview) instead of List of String, we do this:
String QUERY = "SELECT new City(tr.title, tr.review ) from TravelReview as tr";
List<City> cities = session.createQuery(QUERY).list();
I found it very troublesome to purposely create a Java constructor for the purpose above. (It will end up I have many constructors for this.)
Is there a way to map the selected columns automatically and return the original object (TravelReview), only the attributes that match the selected columns have values, the rest of the attributes will be null (or default value)? Basically something like Spring JdbcTemplate BeanPropertyRowMapper which is very useful and convenient.

get all the values in where clause for empty stirng using hibernate

i am building a shopping cart using jsp and hibernate.
i am filtering the content by brand size and price using checkboxes
the checked checkboxes are returned to the class where hql query exists.
so i want i single hql query that can handle this.
as like if one of the parameter like size is empty (means user doesnt uses it to filter the content ) than an empty string is passed to the hql query which returns any value...
so is there anything possible that all values can be retrived in where clause for empty string or some other alternative except coding different methods for different parameter...
I typically use the Criteria api for things like this... if the user does not specify a size, do not add it to the criteria query.
Criteria criteria = session.createCriteria(MyClass.class);
if(size != null && !size.isEmpty()){
criteria.add(Restrictions.eq("size", size);
}
To have multiple restrictions via an OR statement, you use Disjunction. For an AND, you use Conjunction.
Criteria criteria = session.createCriteria(MyClass.class);
Disjunction sizeDisjunction = Restrictions.disjunction();
String[] sizes = { "small", "medium", "large" };
for(int i = 0; i < sizes.length; i++){
sizeDisjunction.add(Restrictions.eq("size", sizes[i]);
}
criteria.add(sizeDisjunction );
First, good practices say that instead of passing and empty String to the query, you should pass null instead. That said, this hql should help you:
from Product p
where p.brand = coalesce(:brand, p.brand)
and p.size = coalesce(:size, p.size)
and p.price = coalesce (:price, p.price)

How to best map results from an SQL query to a non-entity Java object using Hibernate?

I have a Hibernate managed Java entity called X and a native SQL function (myfunc) that I call from a Hibernate SQL query along these lines:
SQLQuery q = hibernateSession.createSQLQuery(
"SELECT *, myfunc(:param) as result from X_table_name"
);
What I want to do is to map the everything returned from this query to a class (not necessarily managed by Hibernate) called Y. Y should contain all properties/fields from X plus the result returned by myfunc, e.g. Y could extend class X and add a "result" field.
What I've tried:
I've tried using q.addEntity(Y.class) but this fails with:
org.hibernate.MappingException: Unknown entity com.mycompany.Y
q.setResultTransformer(Transformers.aliasToBean(Y.class)); but this fails with: org.hibernate.PropertyNotFoundException: Could not find setter for some_property. X has a field called someProperty with the appropriate getter and setter but in this case it doesn't seem like Hibernate maps the column name (some_property) to the correct field name.
q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); returns a Map but the values are not always of the type expected by the corresponding field in X. For example fields in X of type enum and Date cannot be mapped directly from the Map returned by the SQL query (where they are Strings).
What's the appropriate way to deal with this situation?
See the chapter of the documentation about SQL queries.
You can use the addScalar() method to specify which type Hibernat should use for a given column.
And you can use aliases to map the results with the bean properties:
select t.some_property as someProperty, ..., myfunc(:param) as result from X_table_name t
Or, (and although it require some lines of code, it's my preferred solution), you can simply do the mapping yourself:
List<Object[]> rows = query.list();
for (Object[] row : rows) {
Foo foo = new Foo((Long) row[0], (String) row[1], ...);
}
This avoids reflection, and lets you control everything.
Easy. Cast the rows to Map<String, Object>:
final org.hibernate.Query q = session.createSQLQuery(sql);
q.setParameter("geo", geo);
q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
final List<Map<String, Object>> src = q.list();
final List<VideoEntry> results = new ArrayList<VideoEntry>(src.size());
for (final Map<String, Object> map:src) {
final VideoEntry entry = new VideoEntry();
BeanUtils.populate(entry, map);
results.add(entry);
}
First of all you need to declare the entity in the hibernate configuration xml file something like this: .....
class="path to your entity"
Or you can do the same thing programatically before you make the query.

Dynamic Query on multiple properties with Hibernate

I have a model that has several properties. The properties can be primitive (String) or complex (Object). The user can make a query on each primitive property. I would like to know if there is an easy way to build dynamically the query. I use Java and Hibernate.
The model
public class Model {
String prop1;
Point prop2;
List<Shape> prop3;
}
Point and Shape are object that can contains primitives or objects. An example of a query would be all instances where prop1 = "A" and the coordinates are x = 3 and y = 8 and one of the shape is a circle.
prop1 = "A" and prop2.x = 3 and prop2.y and prop3.get(i).type = "Circle"; we would have to iterate on all instances of prop3.
My first idea was unmaintainable and inefficient. It consists in doing queries on all the primitive properties and then merge the results.
Get all instances where prop1 = "A"
Get all instances where prop2.x = 3
and prop3 = y;
Get all instances where one of the
Shape.type = "Circle";
Get the intersection of all 3 sets
Is there any existing library or algorithm that can solve this problem in a better (smarter) way?
Thanks
Have you looked at Criteria queries? It's a Hibernate feature for constructing queries and parameters programmatically.
If your intent is to query for entities that match all of these conditions:
prop1 = "A" and prop2.x = 3 and prop2.y and prop3.get(i).type = "Circle"
with support for association queries, then you could do something like
Criteria criteria = session.createCriteria(Model.class);
criteria.add(Restrictions.eq("prop1", "A"));
criteria.createCriteria("prop2")
.add(Restrictions.eq("x", 3));
.add(Restrictions.eq("y", 2));
criteria.createCriteria("prop3").add(Restrictions.in("type", "Circle"));
List results = criteria.list();
The real strength in Criteria queries is building the query in code rather than in a HQL string - allows you to dynamically add/set properties, etc.

Categories