Hibernate Select Case when empty string - java

I am having problems to implement a search in a PostgreSQl table. The table contains columns with empty strng values that causes an error.
Some information from the column design:
Data type: character varying(20)
Default:
Not NULL: No
Primary key: No
My java class annotation for the column:
#Column(name = "codeClient")
private String codeClient;
This query string works when there is no "empty string" value:
SELECT c FROM Client c WHERE c.id = 765432
And my Json returns:
[{"id":765432,"nameClient":"JACK SMITH","codeClient":"234567890"}]
When I change the query to deal with a empty value:
SELECT c.id, c.nameClient, CASE c.codeClient WHEN '' THEN 'nonexistent' else c.codeClient END FROM Client c WHERE c.id = 765432
The query works, but the Json result misses de columns descriptions:
[[765432,"JACK SMITH","234567890"]]
To solve this problem, I change the query to return an object:
SELECT new ClientDTO(c.id, c.nameClient, CASE c.codeClient WHEN '' THEN 'nonexistent' else c.codeCliente END) FROM Client c WHERE c.id = 765432
But Hibernate can't solve when the result is an empty string:
Java.lang.IllegalArgumentException: org.hibernate.QueryException: could not instatiate class [ClientDTO] from tuple
I've tried to use JPA CriteriaBuilder. It works on simple querys, but due to the complexity, I could not implement a query that I need.
I can't change de database design and I need the Json result.
Anybody can help me?

I would put the CASE c.codeClient WHEN '' THEN 'nonexistent' else c.codeCliente END logic in the DTO:
public ClientDTO(){
...
this.codeClient = ("".equals(codeClient)) ? "nonexistent" : c.codeClient;
...
}
and the leave the query as simple as possible:
SELECT new ClientDTO(c.id, c.nameClient, c.codeClient) FROM Client c WHERE c.id = 765432

You can't instantiate ClientDTO probably because that class is not mapped in persistence.xml. You may change 'new ClientDTO()' to 'new Client()'.

Related

JPA: Using criteriabuilder to find entities: Attribute name different from annotation?

I have a mysql database with employee information, each employee has a technical id as primary key. In MySQL to selcet row(s) matching criteria, i can just use to get the following statement (works)
SELECT * FROM database_test.employee WHERE fist_name='First1';
In Java i can also use this as a native statement to get what i want (works):
List<EmployeeEntity2> objects = m_em.createNativeQuery(
"SELECT * database_test.employee WHERE first_name='First1'",
EmployeeEntity2.class).getResultList();
However, i wanted to use the Criteriabuilder to get the same result and later generalize it for multiple columnName=columnEntry selections.
public List<EmployeeEntity2> testNoParameter() {
//Based on https://www.objectdb.com/java/jpa/query/criteria
CriteriaBuilder cb = m_em.getCriteriaBuilder();
CriteriaQuery<EmployeeEntity2> q = cb.createQuery(EmployeeEntity2.class);
Root<EmployeeEntity2> c = q.from(EmployeeEntity2.class);
ParameterExpression<String> p = cb.parameter(String.class);
//Works
//q.select(c).where(cb.equal(c.get("firstName"), p));
//Won't work
q.select(c).where(cb.equal(c.get("first_name"), p));
TypedQuery<EmployeeEntity2> query = m_em.createQuery(q);
query.setParameter(p, "First1");
List<EmployeeEntity2> results = query.getResultList();
return results;
}
Using "fist_name" - the column name annotation from the Entity - will yield the following java.lang.IllegalArgumentException with:
Unable to locate Attribute with the the given name [first_name] on this ManagedType [xx.xxx.database.EmployeeEntity2]
EmployeeEntity2 has "fist_name" annotation:
#Column(name = "first_name", nullable = false)
#Override
public String getFirstName() {
return super.getFirstName();
}
So "first_name" should exist, however (with some debugging) i found out that the attribute expected is for some reason "firstName" instead - which i have not defined/annotated - so where does it come from - and how can i use the column names actually defined in the database (column = "first_name")?
You should use property name of entity (not column name) to use it in criteria builder so instead of
q.select(c).where(cb.equal(c.get("first_name"), p));
use
q.select(c).where(cb.equal(c.get("firstName"), p));
CriteriaBuilder is RDBMS schema agnostic, so you use your model (entities), not schema (table names etc).
In JPA you dont normally use SQL but JPQL. Equivalent of your SQL in JPQL would be something like
"SELECT e FROM EmployeEntity2 e WHERE e.firstName='First1'"
Both CriteriaQuery tree and JPQL string are transformed down to the same query tree later on (can't remember the name), so they both must comply to the very same rules.

Hibernate Restrictions subquery with id of main query

I got 2 Tables with data
Main
---
id // 1
Second
---
id //1; 2
property //"a"; "b"
creationDate(DD/MM/YYYY) //01/01/2000; 02/02/2002
mainId // 1; 1
The connection is 1-*
So, what I want to do is to query my "Main" table by the property in "Second", but I want to search only the newest property.
So searching "a" must not give any result, as "b" is a newer data.
I wrota it via SQL and it looks like this:
select distinct m.id from Main m join Second s on m.id = s.mainId where s.property = 'b' and s.creationDate = (SELECT MAX(s2.creationDate) from Second s2 where s2.mainId = m.id);
I figured out some java code, but I have no idea how to use this s2.mainId = m.id part via Restrictions:
DetachedCriteria d = DetachedCriteria.forClass(Second.class, "s1");
ProjectionList proj = Projections.projectionList();
proj.add(Projections.max("s1.creationDate"));
d.setProjection(proj).add(Restrictions.eq("WHAT COMES HERE");
Or maybe should I use defferent approach?
Unformtunately I need to use Hibernate Criterion Interface as whole seach mechanismus is written via Criterion.
DetachedCriteria innerCrit = DetachedCriteria.forClass(Second.class);
innerCrit.setProjection(Projections.max("creationDate");
innerCrit.add(Restrictions.eqProperty("id", "main.id"));
DetachedCriteriaouterCrit outerCrit = DetachedCriteria.forClass(Main.class, "main");
outerCrit.createAlias("second", "second");
outerCrit.add(Subqueries.eq(second.creationDate, innerCrit));
outerCrit.add(Restrictions.eq("second.property", "b"));
This outerCrit will get you the Main object.

How to create mapping of composed object with Hibernate when using a complex sqlquery?

I am trying to use the below query with Hibernate's session.createSQLQuery.
The Entity object corresponding to user has an attribute called address.
The address object is created out of 5 fields from table 'user'.
If I do not use an SQLQuery it gets filled auto-magically.
However without the SQLQuery I can't get all the info I would get from the desired joins shown below.
The user entity object also attributes like accessPlan which I am filling up using
.addEntity("accessPlan", AccessPlan.class)
Query:
SELECT
user.*,
ap.*,
country.*,
auth.*,
GROUP_CONCAT(coup.code SEPARATOR ' ') coupons
FROM
user
INNER JOIN access_plan ap ON (user.access_plan = ap.id)
INNER JOIN country ON (user.country=country.code)
LEFT JOIN user_auth auth ON (user.id = auth.userid)
LEFT JOIN (
SELECT
trans.user_id,coupon.code
FROM
payments_transaction AS trans
INNER JOIN payments_coupon coupon ON (trans.payments_coupon_id=coupon.id)
) coup ON (user.id=coup.user_id)
GROUP BY user.id;
What can be the easiest way to fill up the composed address object while using the SQLQuery?
OR
Is there a way to avoid using SQLQuery for a query like this?
Please check below example from the section 'Returning multiple entities'
String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class).list()
In your case, cat = user, mother = address... somewhat like that.
I do not have anything to try out at the moment but I guess this will help.

JPA query with CHAR type. Was: JPA query with WHERE and EmbeddedId

Edit: Cleaning up by removing details not relevant to the problem.
The problem. JPA query returns no results.
String qstr = "select o from MyStats o where o.queue_name = :queue";
String queue = "3";
em.createQuery(qstr).setParameter("queue", queue);
I thought the problem was either in an incorrect syntax of the JPA query or in incorrect annotation of EmbeddedID. Hence I posted definitions of classes involved but told nothing about database table apart from that it was Oracle.
My test code: Read from DB, take first value and re-use that value in subsequent select query meaning that record exists. Should be there, it was just read, right?
Test
String queue = "";
String qstr1 = "select o from MyStats o";
String qstr2 = "select o from MyStats o where o.queue_name = :queue";
logger.debug("SQL query: " + qstr1);
List<MyStats> list = em.createQuery(qstr1).getResultList();
logger.debug("111 Returning results: " + list.size());
for (MyStats s : list) {
queue = s.getQueue_name();
logger.debug("Picking queue name: " + queue);
break;
}
logger.debug("SQL query: " + qstr2);
list = em.createQuery(qstr2).setParameter("queue", queue).getResultList();
logger.debug("222 Returning results: " + list.size());
Output:
SQL query: select o from MyStats o
111 Returning results: 166
Picking queue name: 3
SQL query: select o from MyStats o where o.rec_id.queue_name = :queue
222 Returning results: 0
Class definition
#Entity
public class MyStats {
private String queue_name;
private long stats_id;
... //getters and setters
}
A query without WHERE clause works correctly so as a query with a member of MyStats class.
em.createQuery("select o from MyStats o where o.stats_id = :sid").setParameter("sid", 179046583493L);
I am using Oracle 10 database, Java EE 5 SDK, Glassfish 2.1.
The problem appeared to be with the mapping of Java String type to database column CHAR type.
Database table queue_name column is defined as CHAR(20), while Java type is String.
There are few options to fix it
Replace database column CHAR type with VARCHAR
Pad query parameter value with spaces for every request
Use LIKE condition instead of equals = and add % to the end of parameter value
Speculative: Use cast
(1) Acceptable if you have control over the database table
(2) Works for the given select statement, possibly breaks for JOINs
(3) May fail to do the trick. LIKE 'a%' returns not only 'a ' but 'aa ', 'abc ', and so on
(4) This is not completely clear to me. I am not sure if it is possible to adopt:
em.createNativeQuery("select cast(queue_name as CHAR(20)) from ...");

Hibernate syntax error : Expected DOT

I am getting the following error on the execution of the below hibernate transaction : expecting DOT, found '=' near line 1, column 32 [update t_credential set status = :status , assigned_engine = :engine where id = :id] .
Also, t_credential is a table and not an object. Does hibernate allow to use this way or does it compulsorily have to be an object?
for(Credential credential: accountList){
Query query = ssn.createQuery("update t_credential set status =:status , assigned_engine = :engine where id = :id");
query.setParameter("status", status);
query.setParameter("engine", assignedTo);
query.setParameter("id", String.valueOf(credential.getId()));
int result = query.executeUpate();
}
Look at the HQL example here: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html#batch-direct. It seems that you need to refer to an object: "update t_credential c", and then update it's fields, like this: "set c.status = :status" and so on.
If you want to use Hibernate with SQL Query (and not HQL query), you may have to use a different function.
ssn.createSQLQuery(" ... ");
I never used this function, so I hope it's a good answer for you.
Max

Categories

Resources