JPA mapping entities with hql column names - java

I am trying to use a feature like RowMapper which provides me with ResultSet, so that I can set the attributes of my pojo by taking resultSet.getString("column_name") in JPA.
But JPA doesn't seems to provide such a feature.
StringBuffer rcmApprovalSqlString = new StringBuffer(QueryConstants.APPROVAL_DETAILS_SQL);
List<ApprovalDTO> finalApprovalList = null;
Query rcmApprovalTrailQuery = getEntityManager().createQuery(rcmApprovalSqlString.toString());
rcmApprovalTrailQuery.setParameter(1,formInstanceId);
List<?> approvalList = rcmApprovalTrailQuery.getResultList();
finalApprovalList = new ArrayList<ApprovalDTO>();
for(Object approvalObj : approvalList){
Object[] obj = (Object[]) approvalObj;
ApprovalDTO approvalDTO = new ApprovalDTO();
approvalDTO.setDeptName(obj[0]!=null? obj[0].toString() : NAPSConstants.BLANK_STRING);
approvalDTO.setUserId(obj[1]!=null? obj[1].toString()+" "+obj[2].toString() : NAPSConstants.BLANK_STRING);
approvalDTO.setComment(obj[6]!=null? obj[6].toString() : NAPSConstants.BLANK_STRING);
finalApprovalList.add(approvalDTO);
}
So instead of doing approvalDTO.setComment(obj[6]) which is the 6th element of array, can I do something like approvalDTO.setComment(rs.getString("comments")); ?
So if in future my column position change in the query, I will not have to change my DAO code to match the column number.
My hql query = select ad.departmentid.departmentname, ad.userid.userfirstname, ad.userid.userlastname, ad.napsroleid.napsrolename,
ad.approvalstatus, ad.approvaltimestamp, ad.approvalcomments
from ApprovaldetailsTbl ad
where ad.forminstanceid.forminstanceid = ?1
order by approvallevelid asc

With JPA 2.1 you have a great possibility to use SqlResultSetMapping. You can find out more for example here:
http://www.thoughts-on-java.org/2015/04/result-set-mapping-constructor.html
http://www.thoughts-on-java.org/2015/04/result-set-mapping-basics.html
http://www.thoughts-on-java.org/2015/04/result-set-mapping-complex.html
The idea is that instead of doing it as you used to do:
List<Object[]> results = this.em.createNativeQuery("SELECT a.id, a.firstName, a.lastName, a.version FROM Author a").getResultList();
results.stream().forEach((record) -> {
Long id = ((BigInteger) record[0]).longValue();
String firstName = (String) record[1];
String lastName = (String) record[2];
Integer version = (Integer) record[3];
});
you can introduce an annotation:
#SqlResultSetMapping(
name = "AuthorMapping",
entities = #EntityResult(
entityClass = Author.class,
fields = {
#FieldResult(name = "id", column = "authorId"),
#FieldResult(name = "firstName", column = "firstName"),
#FieldResult(name = "lastName", column = "lastName"),
#FieldResult(name = "version", column = "version")}))
and afterwards use the mapping (by specifying mapping name) in your query:
List<Author> results = this.em.createNativeQuery("SELECT a.id as authorId, a.firstName, a.lastName, a.version FROM Author a", "AuthorMapping").getResultList();

I am able to fetch the desired result only with Native query and not with NamedNativeQuery -
Query rcmApprovalTrailQuery = getEntityManager().createNativeQuery(rcmApprovalSqlString.toString(),"ApprovalMapping");
rcmApprovalTrailQuery.setParameter(1,formInstanceId);
List<ApprovaldetailsTbl> approvalList = rcmApprovalTrailQuery.getResultList();
My native query -
String RCM_APPROVAL_DETAILS_SQL = "select * "+
" from ApprovalDetails_TBL ad " +
" where ad.ApprovalDetailsId = ? ";
SqlResultSetMapping -
#SqlResultSetMapping(name="ApprovalMapping",
entities=#EntityResult(entityClass=ApprovaldetailsTbl.class
))
Note that you need to map all the column names to the entity field names if you are not using * in select query e.g -
fields = {
#FieldResult(name = "col1", column = "alais1"),
#FieldResult(name = "col2", column = "alais2")})

Related

While executing NamedNativeQuery Join query after excluding the primary key using postgresql facing error

I m not required id (primary key) in the resultant output but after excluding id in query and resultset getting error.org.postgresql.util.PSQLException: The column name id was not found in this ResultSet. jpa
SO need help in formatting this entity class.
Note: Assumption should be made like the below metthod call has been made entityManager.createNamedQuery("getPublisherInfoList",PublisherInfoResponseEntity.class).getResultList();
#NamedNativeQueries(value = {
#NamedNativeQuery(
name = "getPublisherInfoList",
query = "SELECT publisher.publisher_name,publisher.contact_name,publisher.contact_email,publisher.contact_phone,publisher.managed_services,\n" +
"annual.customers,annual.employees,annual.revenue,"
"FROM publisher_portal.publisher_informations publisher JOIN publisher_portal.publisher_annual annual\n" +
"ON publisher.publisher_name=annual.publisher_name",
resultSetMapping = "PublisherInfoResponseMappings"
),
#NamedNativeQuery(
name = "getPublisherByName",
query = "SELECT publisher.publisher_name,publisher.contact_name,publisher.contact_email,publisher.contact_phone,\n" +
"publisher.managed_services,annual.customers,annual.employees,annual.revenue,\n" +
"FROM publisher_portal.publisher_informations publisher JOIN publisher_portal.publisher_annual annual\n" +
"ON publisher.publisher_name=annual.publisher_name where publisher.publisher_name= :publisherName",
resultSetMapping = "PublisherInfoResponseMappings"
)
})
#SqlResultSetMapping(name = "PublisherInfoResponseMappings", entities = {
#EntityResult(entityClass = PublisherInfoResponseEntity.class, fields = {
#FieldResult(name = "publisher_name", column = "publisher_name"),
#FieldResult(name = "contact_name", column = "contact_name"),
#FieldResult(name = "contact_phone", column = "contact_phone"),
#FieldResult(name = "contact_email", column = "contact_email"),
#FieldResult(name = "managed_services", column = "managed_services"),
})
})
#Entity
#Table(name="publisher_informations",schema="publisher_portal")
public class PublisherInfoResponseEntity {
#Id
private Long id;
private String publisher_name;
private String contact_name;
private String contact_phone;
private String contact_email;
private String managed_services;
//setters and getters
}
See if you want to exclude some column in resulset simply use #Jsongnore on that particular
column/field in your entity class.
So the solution will be
Include Primary key in query and result set but then use #Jsongnore on primary key so that the prepared resultset won’t have the field id.
Note you can apply #Jsongnore either at field or at getters method
For Example
#NamedNativeQueries(value = {
#NamedNativeQuery(
name = "getPublisherInfoList",
query = "SELECT publisher.id,publisher.publisher_name,publisher.contact_name,publisher.contact_email,publisher.contact_phone,publisher.managed_services,\n" +
"annual.customers,annual.employees,annual.revenue,"
"FROM publisher_portal.publisher_informations publisher JOIN publisher_portal.publisher_annual annual\n" +
"ON publisher.publisher_name=annual.publisher_name",
resultSetMapping = "PublisherInfoResponseMappings"
),
#NamedNativeQuery(
name = "getPublisherByName",
query = "SELECT publisher.id,publisher.publisher_name,publisher.contact_name,publisher.contact_email,publisher.contact_phone,\n" +
"publisher.managed_services,annual.customers,annual.employees,annual.revenue,\n" +
"FROM publisher_portal.publisher_informations publisher JOIN publisher_portal.publisher_annual annual\n" +
"ON publisher.publisher_name=annual.publisher_name where publisher.publisher_name= :publisherName",
resultSetMapping = "PublisherInfoResponseMappings"
)
})
#SqlResultSetMapping(name = "PublisherInfoResponseMappings", entities = {
#EntityResult(entityClass = PublisherInfoResponseEntity.class, fields = {
#FieldResult(name = "id", column = "id")
#FieldResult(name = "publisher_name", column = "publisher_name"),
#FieldResult(name = "contact_name", column = "contact_name"),
#FieldResult(name = "contact_phone", column = "contact_phone"),
#FieldResult(name = "contact_email", column = "contact_email"),
#FieldResult(name = "managed_services", column = "managed_services"),
})
})
#Entity
#Table(name="publisher_informations",schema="publisher_portal")
public class PublisherInfoResponseEntity {
#Id
#Jsongnore
private Long id;
private String publisher_name;
private String contact_name;
private String contact_phone;
private String contact_email;
private String managed_services;
//setters and getters
}
note:assume that entityManager.createNamedQuery(..) has been made

JPA Unknown SqlResultSetMapping [duplicate]

This question already has answers here:
How to map the result set of a JPA NativeQuery to a POJO using SqlResultSetMapping
(11 answers)
Closed 2 years ago.
I have
#SqlResultSetMapping(
name = "OrderDetailsReportMapping",
entities = #EntityResult(
entityClass = OrderDetailsReportDto.class,
fields = {
#FieldResult(name = "orderId", column = "col_0_0_"),
#FieldResult(name = "orgId", column = "col_1_0_")
}))
public class OrderDetailsReportMapping {
}
and OrderDetailsReportDto.class:
public class OrderDetailsReportDto {
private Long orderId;
private Long orgId;
}
and in my OrderManager.class:
StringBuilder queryView = new StringBuilder("SELECT * FROM order_details_report_view");
Query dataQuery = em.createNativeQuery(queryView.toString(), "OrderDetailsReportMapping");
but I got error:
Unknown SqlResultSetMapping [OrderDetailsReportMapping]
Please help. Thanks.
The main problem, I guess, is the usage of entityClass = OrderDetailsReportDto.class in the #SqlResultSetMapping. From Baeldung's tutorial "A Guide to SqlResultSetMapping: 5.1 Single Entity"
EntityResult requires us to specify the entity class
You should use the class annotated with #Entity to store the result.
EDIT#1 for example:
#SqlResultSetMapping(
name = "OrderDetailsReportMapping",
entities = #EntityResult(
entityClass = OrderDetailsView.class,
fields = {
#FieldResult(name = "orderId", column = "first_db_view_col_name"),
#FieldResult(name = "orgId", column = "second_db_view_col_name")
}))
#Entity
#Immutable
public class OrderDetailsView {
#Id
private Long orderId;
private Long orgId;
#Override
public String toString() {
return "OrderDetailsView{" +
"orderId=" + orderId +
", orgId=" + orgId +
'}';
}
}
Query query = em.createNativeQuery(
"select * from order_details_report_view",
"OrderDetailsReportMapping");
List<OrderDetailsView> orderDetailsViews = query.getResultList();
EDIT#2
If "orderId" is not unique you can treat the rownumber as the id column: 1, 2
Tested on Postgres database:
fields = {
added >>> #FieldResult(name = "id", column = "fakeId"),
#FieldResult(name = "orderId", column = "first_db_view_col_name"),
#FieldResult(name = "orgId", column = "second_db_view_col_name")
}
em.createNativeQuery(
added >>> "select row_number() OVER () as \"FakeId\", * "
+ "from order_details_report_view",
"OrderDetailsReportMapping");

JPA native sql query mapping error?

I have a JPA entity MyEntity which includes a composite primary key in a #Embeddable class MyEntityPK.
I am using a native sql query in method getThreeColumnsFromMyEntity():
public List<MyEntity> getThreeColumnsFromMyEntity() {
List<MyEntity> results = em.createNativeQuery("select pid,name,dateofbirth from (select pid,name, dateofbirth,max(dateofbirth) "
+ "over(partition by pid) latest_dateofbirth from my_entity_table) where"
+ " dateofbirth = latest_dateofbirth;","myEntityMapping").getResultList();
return results;
My #SqlResultSetMapping:
#SqlResultSetMapping(
name = "myEntityMapping",
entities = {
#EntityResult(
entityClass = MyEntityPK.class,
fields = {
#FieldResult(name = "PID", column = "pid"),
#FieldResult(name = "NAME", column = "name")}),
#EntityResult(
entityClass = MyEntity.class,
fields = {
#FieldResult(name = "dateofbirth", column = "dateofbirth")})})
My JPA columns are named : #Column(name="DATEOFBIRTH"), "PID" and "NAME".
I tested my sql statement straight on the db and it works fine.
When i run it on Eclipse I get an Oracle error:
ORA-00911 and "Error code 911 , Query: ResultSetMappingQuery [..]
My guess is there is something wrong with the mapping but I cannot find out what it is.
I assume you get this error because you are missing the alias name for the subquery, so instead you can try this :
select
pid,
name,
dateofbirth
from
(
select
pid,
name,
dateofbirth,
max(dateofbirth) over(partition by pid) AS latest_dateofbirth
from
my_entity_table
) second_result
-- ^--------------- use an aliase name to the subquery
where
second_result.dateofbirth = latest_dateofbirth
-- ^----use the aliase name to reference to any of its fields, in your case 'dateofbirth'
Take a look about the error meaning here ORA-00911: invalid character tips

How do I subquery a map for multiple key value combinations in JPA 2.0?

I have the following entity (example):
#Entity
#Table(name = "person")
public class Person implements Serializable {
#Id
#Column(name = "person_id", columnDefinition = "UUID")
private UUID userId;
#Column(name = "name")
private String name;
#ElementCollection
#MapKeyColumn(name = "phonetype")
#Column(name = "number")
#CollectionTable(name = "person_phones", joinColumns = #JoinColumn(name = "userId"))
private Map<String, String> phoneNumbers;
}
Now, the phoneNumbers are String, String in this example. Let's assume the key is the type (like "mobile", "home", "office", "fax", "pager"...) and the value is the actual number in any text format.
I'd like to query for a person which has two phone numbers:
Select * From person where
in his phone_numbers exists phonetype = 'home' and number = '0-123-456'
and also in his phone_numbers exists phonetype = 'mobile' and number = '9-876-421'
(and possibly, dynamically others)
and name = 'John'
I already constructed a sql subquery which works:
select home.userId from
(
(SELECT userId from person_phones
where (phonetype = 'home' and number = '0-123-456'))
) as home,
(
(SELECT userId from person_phones
where (phonetype = 'mobile' and number = '9-876-421'))
) as mobile
where home.userId = mobile.userId
As said, this is just a sql subquery. I'm writing JPA 2.1 criteria query in my project. And this seems oddly complicated. Can anyone give me a hint?
Had a similar problem, solved it using multiple inner joins rather than sub queries.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Person-Test");
EntityManager em = emf.createEntityManager();
Map<String, String> phoneNumbers = new HashMap<>();
phoneNumbers.put("home","0-123-456");
phoneNumbers.put("mobile","9-876-421");
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> personRoot = query.from(Person.class);
query.select(personRoot);
phoneNumbers.forEach((k, v) -> {
MapJoin<Person, String, String> phoneNrJoinJoin = personRoot.joinMap("phoneNumbers");
phoneNrJoinJoin.on(cb.equal(phoneNrJoinJoin.key(), k), cb.equal(phoneNrJoinJoin.value(), v));
});
query.where(cb.equal(personRoot.get("name"), "John"));
List<Person> people = em.createQuery(query).getResultList();
This results in the following hibernate query (renamed aliases for clarity)
SELECT person.person_id, person.name
FROM person
INNER JOIN person_phones a
ON person.person_id = a.userid
AND (a.phonetype = ? AND a.NUMBER = ?)
INNER JOIN person_phones b
on person.person_id=b.userId
and (b.phonetype=? and b.number = ? )
WHERE
person.name = ?;
Which returns all tuples of type person where all the mentioned phone numbers match.

Spring data throws an exception:" No property [property_name] found for type [Object]!"

I would like a Spring Data interface to return a non-entity object.
I have googled and found a solution that I should use named queries with the result set mapping to a non-entity class.
However, I do resieve the described above exception. What causes this exception?
Here is my implementation of the sql result set mapping and named native query:
#SqlResultSetMapping(
name = "revenue",
classes = {
#ConstructorResult(
targetClass = Revenue.class,
columns = {
#ColumnResult(name = "date"),
#ColumnResult(name = "revenue")
}
)
}
)
#NamedNativeQuery(name = "calculateRevenueForGasStationName",
query = "select fueling.date, fueling.price*fueling.volume as revenue from gas_station " +
"left join fueling " +
"on gas_station.id = fueling.gas_station " +
"where fueling.date between ?1 and ?2 and gas_station.name=?3 " +
"group by fueling.date",
resultSetMapping = "revenue")
Here is the spring data interface method that should be linked to a name = "calculateRevenueForGasStationName"
#Query(nativeQuery = true)
List<Revenue> calculateRevenueForGasStationName(Date from, Date to, String name);
It seems problem with your class properties. Can you please revisit your Revenue.class property details.
Please make sure
1) "date" property has declared as java.util.Date
2) revenue has declared as Double
3) Sample code is
`#SqlResultSetMapping(
name = "revenue",
classes = { #ConstructorResult(
targetClass = Revenue.class,
columns = {
#ColumnResult(name = "date", type = java.util.Date.class),
#ColumnResult(name = "revenue",type = Double.class)
} ) } )`

Categories

Resources