I want to get the SearchOutput data object by calling a query(#Query method) with natural joins of 3 tables. but when the query runs it shows an error.
I have tried to fetch the data in my spring boot controller class. But its not working because of the error
package com.example.mysqlproj.model;
import lombok.*;
public class SearchOutput {
private String hotel_name;
private String room_type;
private int price;
}
package com.example.mysqlproj.dao;
import com.example.mysqlproj.model.Room_Type;
import com.example.mysqlproj.model.SearchOutput;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.Collection;
import java.util.Date;
import java.util.List;
public interface RoomTypeDao extends CrudRepository<Room_Type,Integer> {
#Query(value="select new SearchOutput(hotel_name , room_type,(price*(?4)*(?3)*(1.15))) from Room_type natural join Hotel natural join True_contract where (?1 >= start_date and ?2 <= end_date and ?3 <=available_rooms and ?4<= max_adults )", nativeQuery = true)
List<SearchOutput[]> checkHotelList(Date from, Date to, int rooms, int adults, int total_nights);
}
The Error:
No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.mysqlproj.model.SearchOutput]] with root cause
My target is to fetch a searchOutput object array when the query gets called.
Are there any solutions for this. Thanks in advance
The response type from the query is
List<Map<String, Object>> .
Please change the method return type to this.
Related
Lets assume we have one table/View with below columns
columns : ID , Status
I am writing one search API to get Data from backend
I am using org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
.....
#Repository
#Transactional
public interface UIDashboard extends JpaRepository<UIDashboardView, String> {
....
#Query(value = "SELECT results from SearchView results where "
+ "(:status is null or results.STATUS = :status) and"
+ "(coalesce(:ids) is null or results.ID in :ids)"
...
My DTO
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.util.Optional;
import lombok.Data;
#Data
#JsonInclude(Include.NON_NULL)
public class SearchInputDTO {
#JsonProperty(value="status",required = false)
private String status;
#JsonProperty(value="ids",required = false)
//private Optional<List<String>> ids;
//ArrayList<String> ids;
private List<String> ids;
REST API
import org.springframework.web.bind.annotation.PostMapping;
...
#PostMapping("/searchTest")
public ResponseEntity<List<ResultsDTO>> search_test(
#RequestBody #NotNull #Valid SearchInputDTO payload, HttpServletRequest request)
throws IOException {
}
{
"status" : "COMPLETED",
"ids" : [null,null]
}
Issue with the approach is to invoke POST REST API i need to send two null values [null,null] in payload i,e without id's property i am unable to execute POST API , so either i need to send null values or set in DTO.
I also tried to make Optional in DTO or
Used coalesce -> (coalesce(:ids) is null or results.ID in :ids)
i dont want to explicitly send null values in Payload , User can search with any parameter for example only with one property :status:
{
"status" : "INPROCESS"
}
Above payload not working as i am not sending "ids"
Then i tried set nulls in setter as workaround
#JsonProperty(value="ids",required = false)
private List<String> ids = new ArrayList<>(Arrays.asList(null, null));
#JsonSetter("ids")
public void setIds(List<String> li){
if (li != null) {
if (li.size() < 2){
li.add(null);
li.add(null);
this.ids = li;
}
else{
this.ids = li;
}
}
}
I dont like this work around , is there any better solution or changes required to JPQL IN parameter or SearchInputDTO .
I also followed blog Spring Data repository with empty IN clause
Thanks,
Showkath.
I would like to run multiple queries then show results in a page such as :
https://adminlte.io/themes/v3/index.html
I create a first controller query :
package controllers;
import models.Sysuser;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Security;
import views.html.sitemap.index;
import javax.inject.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import play.libs.concurrent.HttpExecutionContext;
import static java.util.concurrent.CompletableFuture.supplyAsync;
import play.db.*;
import io.ebean.*;
import play.Logger;
import java.util.List;
import java.util.ArrayList;
import models.LocationExtractedData;
#Security.Authenticated(Secured.class)
public class SiteMap extends Controller {
private Database db;
private final HttpExecutionContext httpExecutionContext;
private static final Logger.ALogger logger = Logger.of(SiteMap.class);
#Inject
public SiteMap(Database db,
HttpExecutionContext httpExecutionContext) {
this.db = db;
this.httpExecutionContext = httpExecutionContext;
}
public CompletionStage<Result> index() {
return SearchSomething().thenApplyAsync((List<LocationExtractedData> infos) -> {
return ok(views.html.sitemap.index.render( Sysuser.findByUserName(request().username()), infos) );
}, httpExecutionContext.current());
}
public CompletionStage<List<LocationExtractedData>> SearchSomething() {
return CompletableFuture.supplyAsync(() -> {
return db.withConnection(
connection -> {
// Imagines this is a complexe QUERY (Later in the future...)
final String sql = "SELECT sysuser_id, role_id "
+"from sysuser_role "
+"where sysuser_id = '1' "
+"and role_id in ('1','2','3','4','5') ";
final RawSql rawSql = RawSqlBuilder.parse(sql).create();
Query<LocationExtractedData> query = Ebean.find(LocationExtractedData.class);
query.setRawSql(rawSql);
List<LocationExtractedData> list = query.findList();
return list;
});
}, httpExecutionContext.current());
}
}
Can you telling me how to run multiple and optimized queries in the same time for my page full of dashboards, charts and tables!
If i create multiple list of ebeanLists ( queries ), does this will affect the loading of my page ?
IF not, then, what should i do ?
Thank you in advance,
Typically, in an application similar to the link you have provided, you create reusable APIs following the MVC design pattern. Querying the database from the controller is very much against that pattern.
Each API should be atomic, creating a single API to run 1 query to fetch all of the data for that page is not the correct approach.
If you are looking for performance for your API you should get familiar with asynchronous programming. Running your APIs async will allow your back end to process multiple front end requests at the same time, greatly improving performance.
db.getCollection('parentCollection').find({"mapObject.someField" : {$exists: true}})
i want this to convert into method like below
.
#Query("{mapObject.someField :{$exists : true}}")
List<Parent> findByMapKey(String id);
Here i am getting null pointer exception while running application
#Query("{mapObject.someField :{$exists : true}}")
here someField needs to be dynamic not fixed so i want my id to be passed in place of someField
Same question exists here as well
How to get parent object based upon key from child map in MongoRepository JAVA SpringBoot
It's not possible to do with MongoRepository. Instead, use MongoTemplate.
As mentioned above by #Valijon it is not possible with #Query annotation. Still if anyone finds a way please share. Following is how i achieved it using MongoTemplate
package com.somepackage.services;
import org.springframework.stereotype.Service;
import java.util.List;
import com.yourpackagestructure.Parent;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
#Service
public class Service{
private MongoTemplate mongoTemplate;
public Service(MongoTemplate mongoTemplate){
this.mongoTemplate = mongoTemplate;
}
public List<Parent> getParentList(String mapKey){
Query query = new Query();
query.addCriteria(Criteria.where("someMap." + mapKey).exists(true));
List<Parent> parents = mongoTemplate.find(query,Parent.class);
}
}
How convert this procedure execution using #NamedStoredProcedureQuery?
I have this SQL, It's OK!
SQL (it's Works OK):
USE [INTEGRADOR]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[SP_VW_PEDIDOSDECOMPRA_SGM]
#CODIGO = 71648
SELECT 'Return Value' = #return_value
GO
In Java i Try this, but not working. idUsuarioAutenticado is #CODIGO = 71648
JAVA (Error when compile) :
#NamedStoredProcedureQuery(
name = "listarComprasMicrosigaProc",
procedureName = "INTEGRADOR.DBO.SP_VW_PEDIDOSDECOMPRA_SGM",
resultClasses = AcompanhamentoCompraPortalEntity.class,
parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, type = Long.class)
}
)
public List<AcompanhamentoCompraPortalEntity> listarComprasMicrosigaProc(#Param("idUsuarioAutenticado") Long idUsuarioAutenticado);
Not compile.
I received this errors:
The annotation #NamedStoredProcedureQuery is disallowed for this location
My imports (Java) :
import java.util.List;
import java.util.Set;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.StoredProcedureParameter;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Instead of at field/attribute level, you have to add the #NamedStoredProcedureQuery annotation and its details at class level:
#Entity
#NamedStoredProcedureQuery(
// further specifications ...
)
public class MyEntity {
// fields, getter/setter methods, etc.
}
With that corrected, the error (message)
The annotation #NamedStoredProcedureQuery is disallowed for this location
should disappear.
Hope it helps.
I am new to Spring Jpa and Hibernate. I am trying to fetch data using a custom function from an Oracle db. I could define an entity along with its related service, implementation and repository. In addition, I created a new custom Oracle dialect by using registerFunction as you will see below.
So I have two questions:
1) In my Oracle db, the function sits under a different schema. Do I need to specify its schema? If so how? Or will hibernate find it automatically?
I will be asking my second question at the end of this post after providing my full stacktrace...
Here is my full stack trace:
MyOracle10gDialect
package blog;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.dialect.function.StandardSQLFunction;
public class MyOracle10gDialect extends Oracle10gDialect {
public MyOracle10gDialect() {
super();
registerFunction("my_function", new StandardSQLFunction("my_function"));
}
}
application.properties
...
spring.jpa.database-platform=blog.MyOracle10gDialect
...
Entity:
package blog.models;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "item", schema = "WOS_SOURCE")
public class WosItem {
#Id
#Column(nullable = false)
private String UT;
#Column(nullable = false)
private String TI;
public String getUT() {
return UT;
}
public void setUT(String UT) {
this.UT = UT;
}
public String getTI() {
return TI;
}
public void setTI(String TI) {
this.TI = TI;
}
public WosItem(String UT, String TI) {
this.UT = UT;
this.TI = TI;
}
public WosItem() { }
#Override
public String toString() {
return "WosItem{" +
"UT='" + UT + '\'' +
", TI='" + TI + '\'' +
'}';
}
}
Service:
package blog.services;
import blog.models.WosItem;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public interface WosItemService {
List<WosItem> findAll();
WosItem findById(String id);
String find_ut(Long ut_seq);
}
Implementation:
package blog.services;
import blog.models.WosItem;
import blog.repositories.WosItemRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class WosItemServiceJpaImpl implements WosItemService {
#Autowired
private WosItemRepository wosItemRepository;
#Override
public List<WosItem> findAll() {
return this.wosItemRepository.findAll();
}
#Override
public WosItem findById(String id) {
return this.wosItemRepository.findOne(id);
}
#Override
public String find_ut(Long ut_seq) {
return this.wosItemRepository.find_ut();
}
}
Repository:
package blog.repositories;
import blog.models.WosItem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
#Repository
public interface WosItemRepository extends JpaRepository<WosItem, String> {
#Query("SELECT function('my_function', input) FROM WosItem wos");
String find_ut();
}
So in my Oracle db I can use this function as shown below:
select other_schema.my_function(aa.input) from my_schema.TABLE aa;
For ex. say aa.input is 332708100009 then it returns 000332708100009
As for my second question:
2) How can I carry out this process in jpa? I am aware that my repository is not correct at all. I get an error like "Annotations are not allowed here". I could not find a way to remedy this.
Thanks in advance.
EDIT ON THROWN EXCEPTION:
Caused by: java.lang.IllegalStateException: No data type for node: org.hibernate.hql.internal.ast.tree.MethodNode
\-[METHOD_CALL] MethodNode: 'function (my_function)'
+-[METHOD_NAME] IdentNode: 'my_function' {originalText=my_function}
\-[EXPR_LIST] SqlNode: 'exprList'
\-[NAMED_PARAM] ParameterNode: '?' {name=ut_seq, expectedType=null}
Unfortunately if you want to use the JPA 2.1 feature of the custom function call in your Select statement then you will need to perform some additional actions before you can use it.
When you use it in your where statement then it works without any additional actions, but as i wanted to use it for one of my projects inside the select just as you did then you would need to:
1) Extend the hibernate dialect and register your function(s):
package com.mypkg.dialect;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StringType;
public class CustomOracle10gDialect extends Oracle10gDialect {
public CustomOracle10gDialect() {
super();
registerFunction("my_function"
, new StandardSQLFunction("my_function", new StringType()));
}
}
2) Edit your hibernate.dialect property of your session factory to point to that custom implementation:
<property name="hibernate.dialect" value="com.mypkg.dialect.CustomOracle10gDialect"/>
Update
If the function needs to be called from a certain schema then this would be suggested:
registerFunction("my_function"
, new StandardSQLFunction("schema.my_function", new StringType()));
Further reading -> native function calls