Have used containing method in repository for %LIKE% SQL equal in JPA, as below,
Page<Obj> findByNameContaining(String name, Pageable pageable);
which will work like below,
select * from Obj where name like '%John%';
But how do i pass the List<String> names which would query like below using JPA,
select * from Obj where name like '%John%' or name like '%Jiva%' or name like 'etc' .....;
Is there any Spring JPA way for this? i also checked Specification classes too, is that the only way of doing this or am i missing any easy ways or any other dynamic query is recommended?
The most Spring Data JPA way to do this is to use a Specification which adds a like-predicate for every element in the list.
You would call it like so
repository.findAll(containingOneOf(listOfNames))
with Specification containingOneOf(List<String> listOfNames) is a method you need to create.
See https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/ for more details about specifications in Spring Data JPA.
It is not possible to create a query with multiple like operator inside a repository interface But there is a workaround to do this using EntityManager.
EntityManager is extensively used in SimpleJpaRepository. We can get instance of this class using #PersistenceContext like this:
#PersistenceContext
private EntityManager entityManager;
and call its method .createQuery(QUERY).getResultList() to execute a database call. For pagination , You can check this Pagination using entity manager in spring
To create query you can write a simple logic like this:
String createQuery(List<String> names){
StringBuilder query = new StringBuilder("select e from Employee e where ");
int size = names.size();
for(int i = 0; i < size; i++){
query.append("e.name like '%").append(names.get(i)).append("%'");
if(i != size-1){
query.append(" OR ");
}
}
return query.toString();
}
In the above code , Employee is my entity class for which i am creating a select query with multiple like operator.
Complete code:
List<Employee> getEmployees(List<String> names){
String query = createQuery(names);
return entityManager.createQuery(query).getResultList();
}
Related
I am not able to use $where in SpringDataMongoDb.
Is there any way to achieve this in SpringBoot?
db.getCollection('my_collection').find({ $where : function(){
for (var key in this.action_status){
return this.action_status[key] == false;
}
}})
Thank You.
It can be implemented in two ways one is using MongoTemplate and criteria query in spring boot application
Query query = new Query();
query.addCriteria(Criteria.where("action_status").eq(false));
List<User> users = mongoTemplate.find(query,MyCollectionClassName.class);
Another way is using mongo repository
#Query("SELECT mc FROM my_collection mc WHERE mc.status = false")
MyCollectionClassName findMyCollectionClassNameByStatus(Integer status);
References :
https://www.baeldung.com/queries-in-spring-data-mongodb
https://www.baeldung.com/spring-data-jpa-query
1: You can create a repository that extends MongoRepository and have a JSON Query method as follows:
#Query("{'action_status':{$eq:?0}}")
public List<YourObj> findByActionStatus(boolean status);
2: You can use Query By Object Attribute in MongoRepository. Supposedly you have a field called "isActionStatus" in your object, just declare this method in your repository:
public List<YourObj> findByIsActionStatus(boolean actionStatus);
Spring Data will break the method name like "select * from ... where isActionStatus = actionStatus
If you need a more complex query you can find the supported keywords here: https://docs.spring.io/spring-data/mongodb/docs/1.2.0.RELEASE/reference/html/mongo.repositories.html
I'm currently working on a project with Spring and HANA DB.
I have already an Webservice which is working properly, but I need to select a View from my HANA DB(created outside of the Spring Webservice).
My view is made from 2 tables, 4 of its fields are SUM of one column from one of the tables(which counts how much of each of each 4 possible values and shows that as a number in each of the 4 fields).
I read about in some Spring JPA posts that it should work properly with a simple select, my questions are:
I usually make selects like this:
TypedQuery<name_of_the_model_class> query = em.createQuery("SELECT c FROM NameOfTheTable ORDER BY c.some_field DESC WHERE c.name =?1 ", name_of_the_model_class.class);
query.setParameter(1, name_to_search);
And then after that I just return the list to the Controller and the Controller shows that in a JSON.
The problem is, I have created this View in Eclipse, using directly SQL code in HANA DB, without creating it at the Webservice.
I would like to know, is there a way to select like I showed above, returning it without a model class? It would just need a class with exactly the same fields like a model class but without #Entity annotation on it?
OR is there a way to create a view like a model class in Spring JPA? If there is a way, what are the annotations to make it work?
Spring JPA would not accept me to return it without a class would it?
I read plenty posts but didn't found it, even in the Manual it doesn't give clear specification or examples.
Thanks a lot for your time, if I didn't explained it well pls tell me, I'm really stuck on this.
More info(my latest try):
My entire search function at the DAO:
public List<IncidentStatusResultsUser> getIncidentStatusByUser(String userID) throws ParseException {
List<IncidentStatusResultsUser> resultList = em.createQuery("SELECT c FROM USERSTATUS ORDER BY c.uploadDateTime DESC WHERE c.userID=?1 ").setMaxResults(48).getResultList();
Collections.reverse(resultList);
return resultList;
}
I have created a class to just receive the data with the same fields of the view:
public class IncidentStatusResultsUser {
private Date uploadDateTime ;
private int status1;
private int status2;
private int status3;
private int status4;
//All gets and sets ommited
public IncidentStatusResultsUser (Date uploadDateTime, long status1, long status2, long status3, long status4) {
this.uploadDateTime = uploadDateTime;
this.status1= status1;
this.status2= status2;
this.status3= status3;
this.status4= status4;
}
}
EDIT-2: Added public constructor inside the class.
Best Regards,
Famibica
You should be able to map your view to a JPA object as long as it has a primary key (or composite key). You can then map to a Spring JPA Reposiry so your query would go from -
TypedQuery<name_of_the_model_class> query = em.createQuery("SELECT c FROM NameOfTheTable ORDER BY c.some_field DESC WHERE c.name =?1 ", name_of_the_model_class.class);
query.setParameter(1, name_to_search);
To
findBySomeFieldOrderBySomeFieldDesc(String name_to_search)
If you want JPA returning a list of object directly, you need a DTO just like the IncidentStatusResultsUser you created. make sure you have a constructor taking all fields, something like:
public IncidentStatusResultsUser(Date uploadDateTime, int status1, int status2, int status3, int status4)
Then in your query String dtoQuery, you can do:
SELECT new IncidentStatusResultsUser(c.uploadDateTime, c.status1,c.status2,c.status3,c.status4)
FROM NameOfTheTable
ORDER BY c.some_field DESC
WHERE c.name =?1
Then you should be able to call your stuff:
List<IncidentStatusResultsUser> resultList = em.createQuery(dtoQuery).setMaxResults(48).getResultList();
Hope it works for you:)
I am using paging and sorting repository for jquery datatable in my spring project. I tried searching with three parameters as of now like
#Query(value = "Select p from ProfileBaseInfo p where p.fullName = :fullName or p.firstName = :firstName or p.lastName = :lastName")
Page<ProfileBaseInfo> search(#Param("fullName") String fullName,#Param("firstName") String firstName,#Param("lastName") String lastName,Pageable pageable);
Now i need to search 5 more parameters additionally with different combinations(i.e. and/or). I have generated a dynamic query based on the parameters searched. (i.e)If a parameter is present, I will join the table and insert the where condition. How do I bring the dynamically generated query inside of #Query or should I handle this in a different way? Now i what i want is I have to build a criteria like "SELECT * FROM profile where name=? and fullName=? and title=? and city=? and state=? and country=?" in ***#Query*** Annotation.
I would like to know if there is another way to do because the number of columns in a table can be high.
I think you should create a Spring bean with implementation of your search method (Spring Data).
#Autowire some bean to talk with DB (EntityManager or similar) and write down whatever query you need.
I'd recommend you to use some kind of wrapper object for all your parameters, like
class Parameters {
String firstName,
String fullName;
...
Object paramN;
<<getters-setters ?>>
}
and to use CriteriaQuery to construct query according to parameters, like
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<ProfileBaseInfo> cq = cb.createQuery(ProfileBaseInfo.class);
Root<ProfileBaseInfo> from = cq.from(ProfileBaseInfo.class);
...
List<Predicate> predicates = Lists.newArrayList();
...
if (param.getFullName() != null) {
predicates.add(cb.like(cb.lower(ProfileBaseInfo_.fullName)), param.getFullName().toLowerCase() + "%"))
}
...
cb.and(predicates.toArray(new Predicate[predicates.size()]));
So you can expand parameters list accroding to needs and there is no need to work with strings.
I am using spring data JPA in my project. I am playing with millions of records. I have a requirement where I have to fetch data for various tables and build a object and then paint it on a UI. Now how to achieve this my Spring data Repositories. I have read that it can be achieved by Named native queries.
If the named native query does not return an entity or a list of
entities, we can map the query result to a correct return type by
using the #SqlResultSetMapping annotation.
But when I am trying to use #SqlResultSetMapping it is taking another entityResult. Mean what I understand is that it is just transformation some query result to entity result set only, but I want a result set of non - entities objects.
#SqlResultSetMapping(
name="studentPercentile",
entities={
#EntityResult(
entityClass=CustomStudent.class,
fields={
#FieldResult(name="id", column="ID"),
#FieldResult(name="firstName", column="FIRST_NAME"),
#FieldResult(name="lastName", column="LAST_NAME")
}
)
}
)
#NamedNativeQuery(
name="findStudentPercentile",
query="SELECT * FROM STUDENT",
resultSetMapping="studentPercentile")
In above example I am just trying to get a results from student Entity into another pojo 'CustomStudent' which is not a entity. (This example I am trying to execute just for POC purpose, actual usecase is much complicated, with complicated query returning different resultset).
How to achieve above usecase? Is there any other way besides using name query that my repository method returning Non - Entities objects?
You can do something like
#NamedQuery(name="findWhatever", query="SELECT new path.to.dto.MyDto(e.id, e.otherProperty) FROM Student e WHERE e.id = ?1")
Then the MyDto object would just need a constructor defined with the correct fields i.e.
public MyDto(String id, String otherProperty) { this.id = id; this.otherProperty = otherProperty; }
I was deeply surprised when I came accross this for the first time but, yes, you can map query results using #SqlResultSetMapping only to scalars and managed entities.
The best you can do, I guess, is to skip automatic mapping. Query without mapping would return List<Object[]> and you can map it the way you need.
Another approach would be to use #MappedSuperclass. The class denoted as #MappedSuperclass (CustomStudent in your case) can be (not sure 100%, though) used in #SqlResultSetMapping. but you need to introduce inheritance hierarchy, that is your Student entity must extend CustomStudent. That would suck most of the time from the proper OO design, because inheritance would be a little bit artificial...
How about JPA 2.1 ConstructorResult ?
#SqlResultSetMapping(
name="studentPercentile",
classes={
#ConstructorResult(
targetClass=CustomStudent.class,
columns={
#ColumnResult(name="ID"),
#ColumnResult(name="FIRST_NAME"),
#ColumnResult(name="LAST_NAME")
}
)
}
)
#NamedNativeQuery(name="findStudentPercentile", query="SELECT * FROM STUDENT", resultSetMapping="studentPercentile")
We can also parse using JSON help.
Class level declaration.
#Autowired
private EntityManager em;
private ObjectMapper mapper = new ObjectMapper();
Main Code.
Query query = em.createNativeQuery(argQueryString);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String,Object>> result = nativeQuery.getResultList();
List<CustomStudent> resultList = result.stream()
.map(o -> {
try {
return
mapper.readValue(mapper.writeValueAsString(o),CustomStudent.class);
} catch (Exception e) {
ApplicationLogger.logger.error(e.getMessage(),e);
}
return null;
}).collect(Collectors.toList());
I'm trying to find information about how to select only certain fields of an entity using Spring Data (I'm using JPA). I want to select only specific information of an entity, the repository interfaces gives you the ways to return the information of the WHOLE entity!. Some times I only need 2 or 3 fields of an entity and returning 20,30, ...100.. fields may be a little overkill.
This kind of functionality is something that I would do using Hibernate Criteria Projections, or even JPA "SELECT NEW ...." queries. Don't know if it is possible with Spring Data.
Thanks.
What you can do is return a List<Object[]> from repository. Then in your service class iterate over this list and manually create the object you need. Sample repository method
#Query("select el.moduleId, el.threadId from ExceptionLog el")
public List<Object[]> tempQuery();
I think you can also do it in this way
SomeDataPOJO{
required col1
required col2
}
and then write query like this
#Query("select new SomeDataPOJO from requiredTable where xyz="abc")
public List<SomeDataPoJO> tempQuery()
Its not plain Spring Data but did you consider using Springs JdbcTemplate? Its also in the Context if you use Spring Boots Autoconfiguration and has several handlers for transforming results of the Query.
For Example for the Query SELECT a, b FROM EMPLOYEE WHERE ID = ? you could use
String query = "SELECT a, b FROM EMPLOYEE WHERE ID = ?";
List<Pair<String,Integer>> employees = jdbcTemplate.queryForObject(
query, new Object[] { id }, new ExampleRowMapper());
Where the ExampleRowMapper transforms each row from the result into your given Return type (Pair<String, Integer> in this case) and could look like
public class ExampleRowMapper implements RowMapper<Pair<String, Integer>> {
#Override
public Pair<String, Integer> mapRow(ResultSet rs, int rowNum) throws SQLException {
return Pair.of(rs.getString(1), rs.getString(2));
}
}
Example adapted from https://www.baeldung.com/spring-jdbc-jdbctemplate where you find more information.
Of course its not as typesafe as a JPQL as the Query is "raw" or "native" SQL but at least the response is again typesafe and I like it more than to return Object[] or something.