JPA Typed Search Queries - java

I have a rather big model Applicant:
public class Applicant{
private Long id
private String name;
...
...
}
To populate a selection list, I need a list of (id, name) tuples and I use this search query:
public List getNames() {
Query query = em.createQuery("select a.id, a.name from Applicant a");
return query.getResultList();
}
However, I get a list of Object[]'s and I don't really want to convert these in the business layer to the corresponding types (Long and String). What is the best way to approach this? Should I iterate through the list and manually do the type conversion before returning it? Or should I make a helper class:
public class ApplicantTuple{
public Long id
public String name;
public Application(Long id, String name) {
...
}
}
and then have a search query:
Query query = em.createQuery("select NEW my.model.ApplicantTuple(a.id, a.name) from Applicant a");
Or is there a better way to type search queries?

Since you're apparently using JPA2, use the type-safe methods:
public List<Applicant> getApplicants() {
TypedQuery<Applicant> query = em.createQuery(
"select a.id, a.name from Applicant a",
Applicant.class
);
return query.getResultList();
}
Then just use the Objects:
for(Applicant app: getApplicants()){
selectionList.populate(app.getName(), app.getId());
}

Related

org.hibernate.hql.internal.ast.QuerySyntaxException: REPORT Table is not mapped

I have a simple API that expects three parameters and sends a response back, whenever I try to pass the three parameters I end up with an error
org.hibernate.hql.internal.ast.QuerySyntaxException: REPORTS
is not mapped [SELECT e FROM REPORTS e WHERE e.country =
:country AND e.projectId = :projectId AND e.code = :code]
The Model class
#Entity(name = "REPORTS")
#Table(name = "REPORTS")
public class DashboardModel {
public String Country;
public String Project;
public String HtmlContent;
public String FileName;
public String Code;
public String TeamLead;
public String Team;
public DateTime CreateDate;
public DateTime UpdateDate;
//boiler plate code
My Controller
#GetMapping(path = "/report/reportsheet")
public ResponseEntity<String> getReportSheet(#RequestParam("country") String country,
#RequestParam("projectId") String projectId,
#RequestParam("clusterNumber") String clusterNumber){
String report = dashboardService.getReport(country,projectId,clusterNumber);
//String report_ = wallboardService.getStateReportLabelByCountryProjectAndType(country,projectId,reportType);
return ResponseEntity.status(HttpStatus.OK).body(report);
My Service
public String getReport(String country,String projectId,String code){
TypedQuery<DashboardModel> query = entityManager.createQuery(
"SELECT e FROM REPORTS e WHERE e.country = :country AND e.projectId = :projectId AND e.code = :clusterNumber" , DashboardModel.class);
List<DashboardModel> dashboard = query
.setParameter("country", country)
.setParameter("projectId", projectId)
.setParameter("clusterNumber", code)
.getResultList();
return String.valueOf(dashboard);
}
How should I map the table correctly?
You have to use entity class names like DashboardModel in the JPQL and a table name REPORTS in the SQL.
The second parameter DashboardModel.class in the createQuery() is not related to entity class name in the SELECT clause.
You can just use createQuery(jpql) with one parameter, but that method returns a List without element type. So what the second parameter DashboardModel.class for.
You don't need to specify table name here #Entity(name = "REPORTS")
just #Entity
I guess the entity is not in a package that is scanned by Spring Boot. Here is an article about this: https://springbootdev.com/2017/11/13/what-are-the-uses-of-entityscan-and-enablejparepositories-annotations/

Spring hibernate mysql can not fetch the data

In my mysql database I have a table,named:-file_upload
table structure is ;-
I have stored picture in this table..Now I want to fetch the image..
So,I have:--
#Table(name = "file_upload")
public class ProfilePic {
private long id;
private String fileName;
private byte[] data;
--setters and getters with #Column annotation---
public ProfilePic(BigInteger userId) {
super();
this.userId = userId;
}
}
my dao class is:--
public ProfilePic FetchImage(ProfilePic profilePic) {
String hql = "select data from ProfilePic where userId = :userId1 ";
logger.info( profilePic.getUserId());
Query query = (Query) sessionFactory.getCurrentSession().createQuery(hql)
.setParameter("userId1", profilePic.getUserId());
return (ProfilePic) query.uniqueResult();
}
But I am getting error:---
org.hibernate.NonUniqueResultException: query did not return a unique result: 4
why??where is the problem??
This error said that Your query returns 4 rows , that this user has 4 rows in your file_upload table so query.uniqueResult() doesn't return unique result so change query.uniqueResult() to query.List()
use query.uniqueResult() when you guarantee 100% that your query will return only one single result
I don't know if you need to get all the ProfilePic objects associated with that user id or not but you can get the list and choose the one you want
public ArrayList<ProfilePic> FetchImage(ProfilePic profilePic) {
String hql = "select data from ProfilePic where userId = :userId1 ";
logger.info( profilePic.getUserId());
Query query = (Query) sessionFactory.getCurrentSession().createQuery(hql)
.setParameter("userId1", profilePic.getUserId());
return (ArrayList<ProfilePic>) query.List();
}

How to query using an Enum parameter mapped as ORDINAL using JPA and Hibernate

I need to get data from database by enum type.
I have following enum:
public enum ShopType {
VANS("VANS"), ATTICUS("ATTICUS"), FAMOUS("FAMOUS")
ShopType(String label) {
this.label = label;
}
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
In my DAO class i have method which returns list of objects by selected type on jsp page. On jsp page i send selected value like String, is it right?
That how looks my method
#Transactional
public List<Shop> findByType(String type) {
return sessionFactory.getCurrentSession().createQuery("from Shop where type=" + ..... .list();
}
I don't know how to create right query. Enum i store in my database like tinyint.
Here is a model.
#Column(name = "type")
#Enumerated(EnumType.ORDINAL)
private ShopType type;
As you set your enum as ordinal, then in query you should use ordinal. Example;
#Transactional
public List<Shop> findByType(String type) {
return sessionFactory.getCurrentSession().createQuery("from Shop where type=" + ShopType.valueOf(type).ordinal()).list();
}
If you change #Enumerated(EnumType.STRING), then your query will look like;
#Transactional
public List<Shop> findByType(String type) {
return sessionFactory.getCurrentSession().createQuery("from Shop where type=" + ShopType.valueOf(type).name()).list();
}
ShopType.valueOf(type), This will work only if string type is same as enum name.
Also if your label is same as enum name, then you don't need label.
ShopType.VANS.name()is equals"VANS" and name() method is final, you can be sure that can't be overridden.
The problem in your query is that you concatenated the bind parameter value which, apart from causing your issue, may expose your application to SQL injection attacks.
If you write the query using bind parameter values:
Post post = entityManager.createQuery(
"select p " +
"from Post p " +
"where p.status = :status", Post.class)
.setParameter("status", PostStatus.PENDING)
.getSingleResult();
assertEquals("High-Performance Java Persistence", post.getTitle());
Hibernate will properly use the ORDINAL value in the SQL query:
Query:["
select
p.id as id1_0_,
p.status as status2_0_,
p.title as title3_0_
from
post p
where
p.status=?
"],
Params:[
0
]
For a working example, check out the EnumOrdinalTest in my high-performance-java-persistence GitHub repository.
Just convert String to Enum and use named query parameter
#Transactional
public List<Shop> findByType(String type) {
ShopType enumType = shopTypeFromString(type);
return sessionFactory.getCurrentSession().createQuery("from Shop where type=:p_type")
.setParameter("p_type", enumType).list();
}
private ShopType shopTypeFromString(String type) {
// You can implement this convertion in your own way
return ShopType.valueOf(type);
}

How do I tell Hibernate to not create a table for this Entity?

I'm using SqlResultSetMapping and the Entity annotations (SqlResultSetMapping requires an Entity with an Id) to tell Hibernate how to populate instances of Foo with native query results data.
Non-persisted entity:
#SqlResultSetMapping(name = "fooMapping", entities = #EntityResult(entityClass = Foo.class))
#Entity
public class Foo {
#Id
public Long row_id;
public String name;
}
Native query:
String sql = "SELECT id AS row_id, friendlyName AS name FROM SomeTable";
Query q = JPA.em().createNativeQuery(sql, "fooMapping");
List<Foo> fooList = q.getResultList();
The problem is, a table called "Foo" gets created automatically for me (using Play! Framework in dev mode), but Foo is not a model and should not be persisted.
How do I instruct hibernate not to create this table?
Using #ConstructorResult will work great once it's available for your persistence layer. Until then, there is a Hibernate-specific approach using an org.hibernate.SQLQuery and an org.hibernate.transform.ResultTransformer that does not depend on #SqlResultSetMapping. Because a POJO is populated, Hibernate finds no #Entity to automatically turn into a table.
Non-persisted POJO:
public class Foo {
public Long row_id;
public String name;
}
ResultTransformer:
public static class FooResultTransformer implements ResultTransformer {
#Override
public List transformList(List list) { return list; }
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
List<String> aliasList = Arrays.asList(aliases);
Foo foo = new Foo();
foo.row_id = ((Number) getValue(tuple, aliasList, "row_id", 0L))
.longValue();
foo.name = (String) getValue(tuple, aliasList, "name", null);
return foo;
}
private static Object getValue(Object[] tuple, List<String> aliases,
String field, Object defaultValue)
{
// unchecked for berevity
if (tuple[aliases.indexOf(field)] == null) {
return defaultValue;
}
return tuple[aliases.indexOf(field)];
}
}
Native SQLQuery:
String sql = "SELECT id AS row_id, friendlyName AS name FROM SomeTable";
Session session = JPA.em().unwrap(Session.class);
SQLQuery q = session.createSQLQuery(sql);
q.setResultTransformer( new FooResultTransformer() );
List<Foo> fooList = q.list();
Unfortunately this isn't easy...
If you are using JPA 2.1 support for #ConstructorResult (seems there's only support in hibernate 4.3.0.Beta2 so you might not be using), you can use #ConstructorResult as follows:
#SqlResultSetMapping(name="fooMapping",
classes={
#ConstructorResult(targetClass=Foo.class, columns={
#ColumnResult(name="row_id", type=Integer.class),
#ColumnResult(name="name", type=String.class)
})
}
)
public class Foo {
public Long row_id;
public String name;
public Foo(Long rowId, String name) {
...
}
}

use of entityManager.createNativeQuery(query,foo.class)

I would like to return a List of Integers from a
javax.persistence.EntityManager.createNativeQuery call
Why is the following incorrect?
entityManager.createNativeQuery("Select P.AppID From P", Integer.class);
specifically why do I get "...Unknown entity: java.lang.Integer"
Would I have to create an entity class that has a single field that is an Integer ?
Thanks
What you do is called a projection. That's when you return only a scalar value that belongs to one entity. You can do this with JPA. See scalar value.
I think in this case, omitting the entity type altogether is possible:
Query query = em.createNativeQuery( "select id from users where username = ?");
query.setParameter(1, "lt");
BigDecimal val = (BigDecimal) query.getSingleResult();
Example taken from here.
That doesn't work because the second parameter should be a mapped entity and of course Integer is not a persistent class (since it doesn't have the #Entity annotation on it).
for you you should do the following:
Query q = em.createNativeQuery("select id from users where username = :username");
q.setParameter("username", "lt");
List<BigDecimal> values = q.getResultList();
or if you want to use HQL you can do something like this:
Query q = em.createQuery("select new Integer(id) from users where username = :username");
q.setParameter("username", "lt");
List<Integer> values = q.getResultList();
Regards.
Here is a DB2 Stored Procidure that receive a parameter
SQL
CREATE PROCEDURE getStateByName (IN StateName VARCHAR(128))
DYNAMIC RESULT SETS 1
P1: BEGIN
-- Declare cursor
DECLARE State_Cursor CURSOR WITH RETURN for
-- #######################################################################
-- # Replace the SQL statement with your statement.
-- # Note: Be sure to end statements with the terminator character (usually ';')
-- #
-- # The example SQL statement SELECT NAME FROM SYSIBM.SYSTABLES
-- # returns all names from SYSIBM.SYSTABLES.
-- ######################################################################
SELECT * FROM COUNTRY.STATE
WHERE PROVINCE_NAME LIKE UPPER(stateName);
-- Cursor left open for client application
OPEN Province_Cursor;
END P1
Java
//Country is a db2 scheme
//Now here is a java Entity bean Method
public List<Province> getStateByName(String stateName) throws Exception {
EntityManager em = this.em;
List<State> states= null;
try {
Query query = em.createNativeQuery("call NGB.getStateByName(?1)", Province.class);
query.setParameter(1, provinceName);
states= (List<Province>) query.getResultList();
} catch (Exception ex) {
throw ex;
}
return states;
}
Suppose your query is "select id,name from users where rollNo = 1001".
Here query will return a object with id and name column.
Your Response class is like bellow:
public class UserObject{
int id;
String name;
String rollNo;
public UserObject(Object[] columns) {
this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
this.name = (String) columns[1];
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
}
here UserObject constructor will get a Object Array and set data with object.
public UserObject(Object[] columns) {
this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
this.name = (String) columns[1];
}
Your query executing function is like bellow :
public UserObject getUserByRoll(EntityManager entityManager,String rollNo) {
String queryStr = "select id,name from users where rollNo = ?1";
try {
Query query = entityManager.createNativeQuery(queryStr);
query.setParameter(1, rollNo);
return new UserObject((Object[]) query.getSingleResult());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
Here you have to import bellow packages:
import javax.persistence.Query;
import javax.persistence.EntityManager;
Now your main class, you have to call this function.
First you have to get EntityManager and call this getUserByRoll(EntityManager entityManager,String rollNo) function. Calling procedure is given bellow:
#PersistenceContext
private EntityManager entityManager;
UserObject userObject = getUserByRoll(entityManager,"1001");
Now you have data in this userObject.
Here is Imports
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
Note:
query.getSingleResult() return a array. You have to maintain the column position and data type.
select id,name from users where rollNo = ?1
query return a array and it's [0] --> id and [1] -> name.
For more info, visit this Answer
Thanks :)
JPA was designed to provide an automatic mapping between Objects and a relational database. Since Integer is not a persistant entity, why do you need to use JPA ? A simple JDBC request will work fine.

Categories

Resources