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");
Related
I have three tables (I'll list only important fields):
Format
id
template_id
parameterisation_id
Param
name
value
parameterisation_id
ParamDict
name
template_id
I need to map params into formats into one-to-many association, but they do not have direct connection and needed to be joined through ParamDict table.
I currently did it with #JoinTable like so:
#Entity
#Table(schema = "123", name = "format")
public class Format implements Serializable {
#Id
private Long id;
private String template_id;
private String parameterisation_id;
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "paramDict", schema = "123",
joinColumns = {#JoinColumn(name = "template_id", referencedColumnName =
"template_id",insertable = false,updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "param_name", referencedColumnName =
"param_name",insertable = false,updatable = false)})
private Set<Param> params = new HashSet<>()
}
And in sql it looks like this
Select * from
Format f
left join ParamDict pd on f.template_id = pd.template_id
left join Param p on p.name = pd.name;
But now i need to add another condition in Param join:
Select * from
Format f
left join ParamDict pd on f.template_id = pd.template_id
left join Param p on (p.name = pd.name and p.parameterisation_id = f.parameterisation_id);
I tried to add where clause into #Query annotation in my Repository:
public interface FormatRepository extends Repository<Format, String> {
#Query("select n from format f "
+ "left join fetch f.params p "
+ "where f.parameterisation_id in (?1) "
+ "and f.parameterisation_id = p.parameterisation_id"
)
Set<Format> findBypParameterisationIdIn(List<String> ids);
}
And it created right sql query, but Hibernate does not count that condition (f.parameterisation_id = p.parameterisation_id) when mapping query results into class objects, and i get wrong results in Param set (there are items in the params set, that does not have the same parameterisation_id as Format).
How can i do it via Hibernate mapping?
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
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.
I am new in Hibernate, I want to translate the JPQL into Criteria Query while I am learning the CriteriaQuery in Hibernate. I am successfully able to create the JPQL but got Stopped in the criteria. Following is my scenario:
Item Class:
#Entity
#Table(name = "ITEM")
public class Item {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "ITEM_ID")
private Long id = null;
#Version
#Column(name = "OBJ_VERSION")
private int version = 0;
#Column(name = "ITEM_NAME", length = 255, nullable = false, updatable = false)
private String name;
#ManyToOne(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name="itemSellerId")
private User seller;
#Transient
private User buyer;
........
User Class::
...
#OneToMany(fetch=FetchType.EAGER, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
private Set<Item> boughtItems = new HashSet<Item>();
..
My JPQL query which is running fine::
public List<Item> findBySellerOrBuyer(Long sellerId,Long buyerId) {
Query query = entityManager.createQuery("select distinct i from Item i, User u "
+ "where (i.initialPrice > 22 and i.seller.id = :sellerId) "
+ "OR "
+ "( u.id = :buyerId and i member of u.boughtItems and i.initialPrice = i.reservePrice )");
return (List<Item>) query.setParameter("sellerId", sellerId).setParameter("buyerId", buyerId).getResultList();
}
the condition is ::
A Criteria Query that gets Items that match:
a) The Seller & an initial price > 22.0
OR
b) The Buyer & a reserved price = initial price
thanks :)
Last Update
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Item> cr = builder.createQuery(Item.class);
Criterion price = Restrictions.gt("initial price", 22);
Criterion name = Restrictions.eq("seller.id","abc");
Criterion Buyer = Restrictions.eq("buyer.id","abc");
Criterion reserved_price = Restrictions.eq("reserved_price","initial_price");
// To get records matching with AND condition for price & name
LogicalExpression andExp = Restrictions.and(name, price);
LogicalExpression andExp2 = Restrictions.and(Buyer, reserved_price);
return (List<Item>) ((Criteria) cr).list();
Use below code -
Criteria cr = session.createCriteria(Item.class);
Criterion price = Restrictions.gt("initial price", 22);
Criterion name = Restrictions.eq("seller.id","abc");
Criterion Buyer = Restrictions.eq("buyer.id","abc");
Criterion reserved_price = Restrictions.eq("reserved_price","initial_price");
Disjunction objDisjunction = Restrictions.disjunction();
/* Add multiple condition separated by OR clause within brackets. */
objDisjunction.add(Restrictions.and(price , name ));
objDisjunction.add(Restrictions.and(Buyer, reserved_price));
cr.add(objDisjunction);
List results = cr.list();
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")})