Hibernate HQL Left Join Query - java

I have two tables which I need to be joined but there in no relation specified in the entity. Can I write something like
select uc.id, uc.name, mpn.name from UCR uc, MpnMapping mpn
I'm getting an error called Exception in thread "main" org.hibernate.hql.ast.QuerySyntaxException: unexpected token

Yes you can use new operator and a DTO class to set the values..
Query
select new com.example.UCRMNP(uc.id, uc.name, mpn.name) from UCR uc, MpnMapping mpn;
DTO class
First can create a DTO class and specify all the column variables, like this
class UCRMNP{
int id;
String name;
String name1;
public UCRMNP( int id, String name, String name1){
this.id=id;
this.name=name;
this.name1=name1;
}
}
Now you can set the retrieved data to that specific DTO class, You dont want to
annotate it with anything, just specify the constructor and execute
the Query using new operator.

Yes, you can do it by specifing the join in the where clause. It must be something like this:
select a, b from A a, B b where a.joinColumn = b.joinColumn
You can see more info in the below links:
Joining two unrelated tables in hibernate
http://www.codewrecks.com/blog/index.php/2009/09/04/theta-join-in-hql-join-with-unrelated-entities/

Related

How to update #Entity with Spring Projections?

Can I use Spring projections to modify and persist content of existing entities?
My goal is to update only a specific field. Any other fields of that row in the database should remain untouched. Is that possible with projections?
Or is a projection always only readonly?
public void update() {
PersonProjection p = repository.findByLastname("Doe");
p.setLastname("test");
repository.save(p); //how can I save only that field?
}
#Entity
public class Person {
#Id private long id;
private String firstname, lastname, age;
}
interface PersonProjection {
String getLastname();
void setLastname(String lastname);
}
interface PersonRepository extends CrudRepository<Person, Long> {
PersonProjection findByLastname(String lastname);
}
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
Short answer, no, you cannot use Spring Data projections for updates.
What you could do instead if you don't want to fetch the entity beforehand is to write custom queries to update certain fields.
You can do the update with JPQL or Native Queries as well.
I quote the following sources to answer your question:
From this :
SQL SELECT corresponds to the "projection" in relational algebra
And this :
The Relational Algebra was introduced by E. F. Codd in 1972. It
consists of a set of operations on relations:
PROJECT (π): extracts specified attributes (columns) from a relation.
Let R be a relation that contains an attribute X. πX(R) = {t(X) ∣
t ∈ R}, where t(X) denotes the value of attribute X of tuple t.
So projection is only read-only as its name is suggested.
To update just one field , please do it in the normal and correct JPA way which you first get the entity instance , then update its state , and let JPA to figure out how to update it by themselves.

How to convert returned object to required bean/pojo

My requirement is say I have two table:
T1: id,name,email
T2: id,address
To get data from both table I have done like:
Collection ls=null;
EntityManager em=ConnectionUtils.getEntityManager();
tx= em.getTransaction();
tx.begin();
Query q=em.createQuery("select t1.name,t2.address from T1 t1, T2 t2");
ls=(List<T1T2>)q.getResultList();
OP:[[Ljava.lang.Object;#e836bd1, [Ljava.lang.Object;#561b6dc8,
[Ljava.lang.Object;#22c491a2, [Ljava.lang.Object;#17353483,
[Ljava.lang.Object;#260a905c, [Ljava.lang.Object;#7f8b9b86,
[Ljava.lang.Object;#268fbbd5, [Ljava.lang.Object;#2674b0ba,
[Ljava.lang.Object;#36fe970f, [Ljava.lang.Object;#46f75fe,
[Ljava.lang.Object;#31ab78f8, [Ljava.lang.Object;#7092fb41,
[Ljava.lang.Object;#41ada224, [Ljava.lang.Object;#6e700b2b]
ya its annoying.
I am getting data but its an normal Object.
I have created pojo as:
T1T2: String name;String address; to get returned object in this
format. but getting proper format instead Entity error and that pojo
is not error.
I want same type of concept as marshalling of json string to corresponding pojo.
If you want to use JPA for mapping to POJO's use #SqlResultSetMapping annotation
Assuming T1T2 has a constructor T1T2(String name, String address) add this to any of your entity class definition
#SqlResultSetMapping(name = "CUSTOM_MAPPING", classes = #ConstructorResult(
targetClass = T1T2.class,
columns = {#ColumnResult(name = "name", type = String.class),
#ColumnResult(name = "address", type = String.class)}))
Now you can use this mapping:
Query q=em.createNativeQuery("select t1.name,t2.address from T1 t1, T2 t2","CUSTOM_MAPPING");
List<T1T2> = q.getResultList();
Note that it work only on native queries. I'm assuming that there is no association defined at JPA entity level between T1 and T2, otherwise whole process is obsolete. If there is an association, use #JoinTable annotation to declare it and JPA will make sure to fetch association along with entity.
In case you don't need full ORM functionality (or do not know how to do it properly), you can accomplish your task with Spring's JdbcTemplate:
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List<T1T2> pojos = jdbcTemplate.query(
"SELECT t1.name, t2.address FROM T1 t1 JOIN T2 t2 ON t1.id=t2.id",
new BeanPropertyRowMapper(T1T2.class));
BeanPropertyRowMapper maps result set columns to POJO fields that have the same name, respecting field types.
Mapping JPQL Query Result to POJO
When you execute the query
Query q=em.createQuery("select t1.name,t2.address from T1 t1, T2 t2");
Collection c = q.getResultList();
you'll get a collection of zero or more instances of arrays of type Object. If you want the result of the query be mapped to a POJO, you can use the so called Construcot Expression. To use it, first define your POJO as follows with an appropriate constructor:
package com.myproject.dto;
public class T1T2 {
private String name;
private String address;
public T1T2() {}
public T1T2(String name, String address) {
this.name = name;
this.address = address;
}
// getters + setters
}
Then you can formulate your query as follows:
String queryString = "SELECT NEW com.myproject.dto.T1T2(t1.name, t2.address) FROM T1 t1, T2 t2";
TypedQuery<T1T2> q = em.createQuery(queryString, T1T2.class);
Collection<T1T2> result = q.getResultList();
Now you should have a collection of zero or more POJO instances and you don't need to cast.
Here is an extract from the JPA 2.0 Spec if you want to understand the details:
4.8.2 Constructor Expressions in the SELECT Clause
A constructor may be used in the SELECT list to return an instance of a Java class. The specified class is not required to be an entity or to be mapped to the database. The constructor name must be fully qualified.
If an entity class name is specified as the constructor name in the SELECT NEW clause, the resulting entity instances are in the new state.
If a single_valued_path_expression or identification_variable that is an argument to the constructor references an entity, the resulting entity instance referenced by that single_valued_path_expression or identification_variable will be in the managed state.
Note: Your query is building a x-product, do you really want that? As of now, you'll get any name with any address.

Hibernate get field of the object stored in map in the select clause

I have the class structure like this:
Class A {
private HashMap<\String, B> someFieldMap = // Retrieves some map
//getter for someFieldMap
//setter for someFieldMap
}
B is a custom class with the following structure.
class B {
private String type;
private String value;
//getters and setters for the above fields
}
Now, I'm trying to write a HQL to retrieve the value in class B
select value(fieldMap) from A a join a.someFieldMap fieldMap
where index(fieldMap) = 'xyz' //index(fieldMap) will give me the Key of the map.
value(fieldMap) gives me the entire object of instance B. so it will give me the whole object whose type is B.
I want to select b.value and b.type through the select clause.
I tried (value(fieldMap)).value, (value(fieldMap)).getValue() but it doesn't work. I tried to search this up but couldn't find anything.
Try this:
SELECT fieldMap.value, fieldMap.type
FROM A a join a.someFieldMap fieldMap
WHERE index(fieldMap) = 'xyz'

Hibernate/JPA: Is it possible to retrieve heterogeneous entities in a single query?

I have 2 entities: EntityA and EntityB.
They are unrelated, and I cannot put them in a Inheritance tree for some restrictions out of the scope of this question.
But I need to get in the same JPQL or HQL query a mixed List containing all the instances of both entities. Is this possible with JPA or even Hibernate directly?
I need somethign like this:
FROM EntityA WHERE fieldA=1
UNION
FROM EntityB WHERE fieldB="aa"
Any hint?
Well, I finally figured it out.
It is enought to make the entities implement a common interface (it is not even needed to declare this interface on Hibernate).
Then, a query like this can be done:
FROM my.package.CommonInterface obj
WHERE obj IN (FROM EntityA WHERE fieldA=1) OR
obj IN (FROM EntityB WHERE fieldB='a')
This way, you retrieve a List<CommonInterface>.
Problem solved.
Best thing is to performs two queries.
But if you must:
You can create a POJO to retrieve them:
class EntityAandEntityB {
EntityA a;
EntityB b;
long idA;
long idB;
int fieldA;
String fieldB;
public EntityAandEntityB(long idA, long IdB, int fieldA, String fieldB) {
this.a = new EntityA(idA, fieldA);
this.b = new EntityB(idB, fieldB);
}
}
Then your query would be:
select new package.EntityAandEntityB(a.idA, a.fieldA, b.idB, b.fieldB) from (
(select idA, fieldA from EntityA) a
UNION
(select idB, fieldB from EntityB) b)
This is dirty and you probably must to look carefully the syntax.
Regards.

Defining the order of a list

I have the following problem. I have three classes, A, B and C. A contains a OneToMany relationed list of B:s. B contains a ManyToOne relation to C. C contains a field called "name" and B also contains a field called "name". What I'd like to accomplish is to have the items in A's list sorted primarily by C's name and secondarily by B's name - the problem is that I do not know how to do this. Is it even possible?
I'm using EclipseLink as my JPA provider.
class A {
#OneToMany
#OrderBy("b.c.name, b.name") <---- this is the problem
List<B> b;
}
class B {
#ManyToOne
C c;
String name;
}
class C {
String name;
}
EDIT
Yes, I've tried different variations, for example #OrderBy("c.name") doesn't work, I just get an error message telling me that the entity class b does not contain a field called "c.name".
It's NOT possible. #OrderBy only accepts direct property / field names, not nested properties. Which makes sense, really, because "c" table - depending on your fetching strategy may not even be part of a select issued to retrieve your "b"s.
ChssPly76 is right.
What you could do is to create a named query like this one:
SELECT b
FROM B b
WHERE b.a = :mya
ORDER BY b.c.name
Have you tried #OrderBy("c.name", "name") ?
You shouldn't use "b." because it's implied that the #OrderBy will be done on columns of the instances of B on the b array.
Have you tried:
#OrderBy("c.name ASC", "name ASC")
?
It is not possible in javax.persistence.OrderBy (as say ChssPly76 ), but when I was using Hibernate I construct new column in PLAIN SQL with Formula() annotation and then OrderBy over it:
class A {
#OneToMany
#OrderBy("orderCol") <---- reference to virtual column
List<B> b;
}
class B {
#ManyToOne
C c;
String name;
#org.hibernate.annotations.Formula(
"( select C_table.name as orderCol from C_table where C_table.id = id )"
) <------------------------------------------ join with plain SQL statment
String orderCol;
}
May be EclipseLink has same possibilities?

Categories