How to use CreateNativeQuery to query single value from SQL database value? - java

using a CRUD and want o access a certain value in the databse. what I tried is:
Query query = em.createNativeQuery("select o from Table o where o.IDfield= '938'");
Table o = (Table)query.getSingleResult();
but this fails.
Any suggestions?

Your select looks like a jpql query so it won't work when passed directly to the database as a native query. You can use the createQuery method instead. Even better would be to use a named parameterized query declared on your entity like this:
#Entity
#NamedQueries({#NamedQuery(name="MyEntity.findById", query="select o from MyEntity o where o.IDfield = :id"})
public class MyEntity {
#Id
private String IDfield;
}
...
MyEntity entity = (MyEntity)em.createNamedQuery("MyEntity.findById").setParameter("id", "938").getSingleResult();

Related

Dynamic Query Instead of #subselect when giving an Entity data

I got the following entity:
#Entity
#Immutable
#Subselect("select distinct r.code, r.dsc\r\n"
+ "from roles r, accesses a\r\n"
+ "where r.code = '12'\r\n")
#MasterEntity(labelCode = "Scenario")
public class Scenario implements java.io.Serializable {
I want to use a dynamic query (or parameterized) instead of this static query.
for example: r.code should be equal to a parameter variable not "12"
is there a replacement for #Subselect while I use #Immutable?

Query by other entity's id in JPA repository

I have an SQL database with two related tables, my_entities and custom_entities.
The my_entities table has the columns id, custom_entity_id.
In my Groovy code, both are handled using Entity classes:
#Entity
class MyEntity {
#ManyToOne(fetch = EAGER)
#JoinColumn(name = "custom_entity_id")
CustomEntity customEntity
[...]
}
and
class CustomEntity {
#Id
#GeneratedValue(generator = "pooled")
#GenericGenerator(name = "pooled", strategy = "org.hibernate.id.enhanced.TableGenerator", parameters = [
#Parameter(name = "value_column_name", value = "sequence_next_hi_value"),
#Parameter(name = "prefer_entity_table_as_segment_value", value = "true"),
#Parameter(name = "optimizer", value = "pooled"),
#Parameter(name = "increment_size", value = "100"),
#Parameter(name = "initial_value", value = "100")])
Long id
[...]
}
I have a JPA repository MyEntityRepository class for querying the my_entity table:
#Repository
interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
[...]
}
In MyEntityRepository, I am trying to implement a findByCustomEntityIds() method like this:
#Query("""
select e
from MyEntity e
where e.deleted = false
and e.customEntity in :ids
""")
List<TestCollectionQuery> findByCustomEntityIds(#Param("ids") List<Long> ids)
In MySQL, the query is rather simple (for instance with id 2400), clearly no joins required:
SELECT t.* FROM my_entities t WHERE custom_entity_id in (2400);
Apart from the automatic translation from underscores to camel case, the trailing _id in the SQL table column name is stripped; otherwise, the code does not compile.
I also have a custom Groovy class which calls that method:
class MyClass {
#Autowired
MyEntityRepository myEntityRepository
List<MyEntity> getEntities(List<Long> customEntityIds) {
return myEntityRepository.findByCustomEntityIds(customEntityIds)
}
The call raises the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value element [2400] did not match expected type [...CustomEntity (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value element [2400] did not match expected type [...CustomEntity (n/a)]
[...]
Caused by: java.lang.IllegalArgumentException: Parameter value element [2400] did not match expected type [...CustomEntity (n/a)]
From the error message, I understand that the input should be a list of CustomEntity objects, instead of IDs (Long).
A potential workaround seems to be querying the custom_entities table in order to convert the custom entity ids from Long to CustomEntity objects.
However, that would require adding a JPA CustomEntityRepository, and seems very inefficient. It would require an additional database call just for the purpose of converting IDs into objects, so that I can eventually query for the IDs (which I already have had to begin with) in the my_entities table.
The reason why I have the IDs for the custom entities, but not the objects, is that they are provided by user input further up the line.
My question is thus: how can I implement a method in the MyEntityRepository that implements the MySQL query stated above based on a list of custom entity IDs, without converting them from Long into CustomEntity objects?
Or is there a more fundamental flaw in my design?
The query should end in "and e.customEntity.id in :ids" not in "and e.customEntity in :ids".

JPA: Check if Collection has member with property

In my software, I have an entity (let's call it Member) with a collection of another entity (let's call it State). The query I need to write should return all members who have no State with a specific property value (e. g. 5).
Here are the relevant parts of the entities:
public class Member {
#JoinColumn(name = "MEMBER_ID")
#OneToMany
private List<State> states;
#Column
private String name;
}
public class State {
#Column
private int property;
}
Note that there is no bidirectional mapping between Member and State, the mapping is declared on the non-owning side of the relation (Member). In SQL I would create a query like this:
SELECT m.name
FROM Member m
WHERE NOT EXISTS (
SELECT *
FROM State s
WHERE
m.id = s.member_id
AND s.property = 5
);
But I don't know of any way to achieve the same thing in JPQL without having a mapping on the owning side of the relation. Is there any way to achieve this without having to bother with bidirectional mappings?
JPA allows to use collection references in subquery from clauses, so you can use this:
SELECT m.name
FROM Member m
WHERE NOT EXISTS(
SELECT 1
FROM m.states s
WHERE s.property = 5
)
This will produce exactly the SQL you want.
you can write native query like this
select name from Member where member_id not in ( select id from states
where property = 5)
Try something like this
select m.name from Member m where not exists(
from Member m1 join m1.states s where s.property = 5
)
or
select m.name from Member m where m.id not in(
select m1.id from Member m1 join m1.states s where s.property = 5
)

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/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.

Categories