Spring data projection for native query not mapped to interface - spring

This my repostoriy for retrieve items
#Query(value = "SELECT DISTINCT M.ID as \"id\", "
+ " M.NAME_PRIMARY_LANG as \"name\" "
+ " FROM ECOMMERCE_CORE.MERCHANT_ITEMS M , "
+ " ECOMMERCE_CORE.PRODUCT_UNIT_OF_MEASURE P , "
+ " ECOMMERCE_CORE.LOOKUP_TYPES_STATUS S , "
+ " ECOMMERCE_CORE.ITEM_TYPES T , "
+ " ECOMMERCE_CORE.ITEM_PRICE I,"
+ " ECOMMERCE_CORE.MERCHANT_ITEM_BRAND B, "
+ " ECOMMERCE_CORE.MERCHANT_ITEM_CATEGORY C "
+ " WHERE M.ID = P.PRODUCT_ID AND M.ID=I.PRODUCT_ID AND M.ID = B.MERCHANT_ITEM_ID AND S.ID=M.STATUS_ID AND M.TYPE = T.ID AND M.MERCHANT_ID =?1 AND M.STATUS_ID =?2 "
+ " AND P.BRANCH_ID = ?3 AND I.CHANNEL_ID = ?4 ",
nativeQuery = true
)
List<ItemModelProjection> findBySupplierIdAndStatusCode(long id, long status, long branchId, long channelId, Pageable pageable);
and this my interface which i need to map the result to it
#Getter
#EqualsAndHashCode(of = {"id"})
public class ItemModelProjection {
private String id;
private String name;
public ItemModelProjection(final String id, final String name) {
this.id = id;
this.name = name;
}}
and the result of this query not mapped to the interface , what is the problem for it ?

You can solve this issue and achieve the result by using projections by making your DTO an interface with getters for columns returned by the query.
All you need to do is to have interface and contain query domains starting with get.
public interface ItemModelProjection {
Long getId();
String getName();
}

You need an interface if you want to retrieve those values. And be careful with the naming of the methods. If you have like in your case AS name then call the method getName(). But if you don't have AS specified and you are returning a value for example like PRODUCT_UNIT_OF_MEASURE then use the following method name: getProduct_Unit_Of_Measure().
For getting those two values use the following interface:
public interface ItemModelProjection {
String getId();
String getName();
}

Related

Conversion type error with native JPA query

I wrote a native query to get the top 5 tags for questions, I created a class to hold the returned data - which is only the tag name and the total number of occurrences, but I get a type conversion error that I don't understand.
#Query(value = "select distinct t.naam as name, count(t.id) as total from vragen_tags vt " +
"left join tags t on vt.tag_id = t.id " +
"left join vragen v on vt.vraag_id = v.id " +
"where v.actief = true " +
"group by t.naam " +
"order by total desc " +
"limit ?1", nativeQuery = true)
Set<TagAndCountResponse> getTopTags(int limit);
Class:
public class TagAndCountResponse {
private String name;
private int total;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
}
But I get this error:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [be.ambrassade.jeugdlink.model.response.TagAndCountResponse]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
...
What is causing this error?
I found the answer through another medium. (kudos to Les) The solution is to use projections (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections), so in my case rewriting the concrete class to this interface makes it work.
public interface TagAndCountResponse {
String getName();
int getTotal();
}

i get "path expected for join" and Query exception: unable to resolve path [Product.ProductID]

I have two models:
#Entity
public class Product{
#Id
private String ProductID;
private String ProductName;
#ManyToOne
#JoinColumn
private Supplier supplier;
private int quantity;
private int price;
//getter setter...
//constructor...
}
#Entity
public class Supplier {
#Id
private String SupplierID;
private String SupplierName;
private String Phone;
private String Address;
private String Email;
//getter setter
//constructor
}
In jdbc template of spring i can get all record i want like this:
public List<Product> getProducts(int take, int skip){
List<Product> list = new ArrayList<Product>();
String sql = "SELECT product.ProductID, product.ProductName, product.Quantity, supplier.SupplierID"
+ ", supplier.SupplierName, product.Price"
+ " FROM product INNER JOIN supplier ON product.SupplierID = supplier.SupplierID"
+ " LIMIT " + skip + "," + take + "";
list = jdbcTemplate.query(sql, new ProductMapper());
return list;
public class ProductMapper implements RowMapper<Product> {
public Product mapRow(ResultSet rs, int line) throws SQLException {
Product product = new Product();
product.setProductID(rs.getString("ProductID"));
product.setProductName(rs.getString("ProductName"));
product.setQuantity(rs.getInt("Quantity"));
product.setSupplier(new Supplier(rs.getString("SupplierID"), rs.getString("SupplierName")));
product.setPrice(rs.getInt("Price"));
return product;
}
But it's wrong in hibernate:
//--------hibernate-------
Session session = sessionFactory.openSession();
session.beginTransaction();
String queryStr = "SELECT Product.ProductID, Product.ProductName, Product.Quantity, Supplier.SupplierID"
+ ", Supplier.SupplierName, Product.Price"
+ " FROM Product INNER JOIN Supplier ON Product.SupplierID = Supplier.SupplierID";
List<Product> list = new ArrayList<Product>();
try {
Query query = session.createQuery(queryStr);
query.setFirstResult(skip);
query.setMaxResults(take);
list = (List<Product>) query.list();
session.getTransaction().commit();
}
catch(Exception e) {
System.out.println("Exception e" + e);
session.getTransaction().rollback();
}
finally {
session.close();
}
return list;
}
i get "path expected for join" and Exception eorg.hibernate.QueryException: Unable to resolve path [Product.ProductID], unexpected token [Product] [SELECT Product.ProductID .... ]
Anyone can help me to get the same result when i do with jdbc template.
SELECT p.ProductID, p.ProductName, p.Quantity, s.SupplierID, s.SupplierName, p.Price
FROM Product p
INNER JOIN p.Supplier s
You need to use paths in your HQL query, from one entity to the other. The Hibernate documentation on HQL and joins provides more information here.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#queryhql-joins
String sql = "SELECT product.ProductID, product.ProductName,
product.Quantity, supplier.SupplierID"
+ ", supplier.SupplierName, product.Price"
+ " FROM product INNER JOIN supplier ON product.SupplierID = supplier.SupplierID"
+ " LIMIT " + skip + "," + take + "";
If you are using sql query then you need to give SQL table and sql table columns,
But here you are mixing SQL table and Java Classes , like
product is probably a SQL table and Product is the entity class.
So change your query as
String sql = "SELECT p.ProductID, p.ProductName, p.Quantity, s.SupplierID"
+ ", s.SupplierName, s.Price"
+ " FROM Product p INNER JOIN Supplier s ON p.SupplierID = s.SupplierID"
+ " LIMIT " + skip + "," + take + "";
Also, your variable names are not in camelCase, this can mess up Hibernate's way of mapping a Entity property to table columns, so pay special attention to getter and setters .

nested exception is org.hibernate.HibernateException: Could not instantiate resultclass

what is wrong ?
public List < ReportDTO> listProductAll() {
String sql
= "select "
+ "ip.product_name as productName, "
+ "ip.base_price as basePrice, "
+ "iu.username as username "
+ "from tb_buy a "
+ "left join in_product ip on a.id_product = ip.product_id "
+ "left join im_users iu on a.id_user = iu.user_id ";
Query q = identifyServer.getCurrentSession().createSQLQuery(sql)
.addScalar("productName")
.addScalar("basePrice")
.addScalar("username")
.setResultTransformer(Transformers.aliasToBean(ReportDTO.class));
return q.list();
}
public class ReportDTO {
private String productName;
private Double basePrice;
private String username;
public ReportDTO(String productName, Double basePrice, String username) {
this.productName = productName;
this.basePrice = basePrice;
this.username = username;
}
// getter setter
org.springframework.orm.jpa.JpaSystemException: Could not instantiate resultclass: ReportDTO; nested exception is org.hibernate.HibernateException: Could not instantiate resultclass: ReportDTO
solve
public ReportDTO() {}
Hibernate requires all entities to have a default no args constructor.
If your entity class doesn't have it, or if it's not public, you'll get this exception.

Jest mapping with getSourceAsObjectList()

I tried to map elastic data to list. since getSourceAsObjectList() method is deprecated, I made code like this.
class activityObj {
private String name;
private String oid;
public String getName()
{
return name;
}
public void setName( String name)
{
this.name = name;
}
public String getOid()
{
return oid;
}
public void setOid( String oid)
{
this.oid = oid;
}
}
List< Hit<activityObj, Void>> hits = result.getHits(activityObj.class);
List< activityObj> list = new ArrayList<activityObj>();
for (SearchResult.Hit<activityObj, Void> hit: hits) {
activityObj objectSource = hit.source; // null point error
list.add(objectSource);
logger.info( "hits : " + objectSource.getName());
}
It doesn't work as I expect and looks messy ( it's using two list value to map result). Am I doing wrong?
Michael's answer helped me and is a nice way to do it. Here's what I came up with including all the parts I used to make the query and get the result.
In my case I wanted to get a list of user ids collected from the source of each document in the result.
class DocSource {
private Integer userId;
public Integer getUserId() {
return userId;
}
}
String query = "{\n"
+ " \"_source\": [\n"
+ " \"userId\"\n"
+ " ],\n"
+ " \"query\": {\n"
+ " <some query config here>"
+ " }\n"
+ " }\n"
+ "}";
Search search = new Search.Builder(query)
.addIndex("my-index")
.build();
SearchResult result = jestClient.execute(search);
List<SearchResult.Hit<DocSource, Void>> hits = result.getHits(DocSource.class);
List<Integer> listOfIds = hits.stream()
.map(h -> h.source.getUserId())
.collect(Collectors.toList());
Have you tried something like this:
List< activityObj> list = hits.stream().map(h -> h.source).collect(Collectors.toList());

spring data neo4j crud - many optional param?

I use Spring-data-neo4j with one CrudRepository
#Repository
public interface PersonRepository extends GraphRepository<Person> {}
I have a Html form with 3 inputs FirstName, Name, Age, so I have possible a multiple criteria choose : All, FirstName, FirstName + Name, FirstName + Age etc....
I would like to make a "multiple criteria find" with Map or other stuff. Is it possible?
I try this in my CRUD:
List<Person> findByFirstnameAndNameAndAge(String firstname, String name, int age);
but it's not work if one or all parameters is null.
Try to use a map and a #Query annotation
#Query("MATCH (u:Person) WHERE u.name = {param}.name OR u.age = {param}.age RETURN u")
List<Person> findDynamic(#Param("param") Map params);
Hi #Michael Hunger Thank you for your response. It's not exactly what I expected but you delivered me some fine search stuff
finally I do this :
import org.apache.commons.collections.map.HashedMap;
import com.google.common.collect.Lists;
(...)
#Autowired
private EventRepository eventRepository; //#Repository extends GraphRepository<Event>
(...)
public List<Event> findByDynamicParam(HashedMap params) {
String query = "match (event)-[:user]-(user), (event)-[:action]-(action)";
if (!params.isEmpty()) {
query += " where";
}
if (params.containsKey("actionId")) {
query += " id(action) = {actionId} and";
}
if (params.containsKey("userId")) {
query += " id(user) = {userId} and";
}
if (!params.isEmpty()) {
query = query.substring(0, query.length() - 4);
}
query += " return (event)";
return Lists.newArrayList(eventRepository.query(query, params));
}
client's caller :
HashedMap params = new HashedMap();
if (actionId != null) {
params.put("actionId", actionId);
}
if (userId != null) {
params.put("actionId", userId);
}
List<Event> events = eventService.findByDynamicParam(params);
What do you think? Is it possible to optimize this function?
Regards
Olivier from Paris

Resources