delete in list via Panache in Quarkus - quarkus

Here’s what I want to do
delete from table where id in list_of_ids
I know Hibernate HQL can do that
Long[] ids = {1L, 2L, 3L};
Query query = session.createQuery("delete from SysMenu where id in (:id)");
query.setParameterList("id", ids);
int i = query.executeUpdate();
But what can I do if I want to use Panache-ORM?

with panache you can always use a simplified query, something like
SysMenu.delete("delete from SysMenu where id in ?", ids);
should work (handwritten, not tested).
Here you can see the method definition

It works with Panache
Long[] ids = {1414151951951728640L, 1414152114971742208L};
List<Long> list = Arrays.asList(ids);
long rows = SysMenu.delete("id in (?1)", list);

Related

How to get Distinct record from JPA

I have implemented a method which gives me specification, but what I want is the query should be as below:
Select Distinct *
From (another select query)
I generate query dynamically.
How do I perform the same using specification in Spring Boot?
Try something like this
Specification<T> spec = getSpecification();
Specification<T> distinctSpec = (root, query, cb) -> {
query.distinct(true);
return spec.toPredicate(root, query, cb);
};
if you want to get distinct records, you have to write a query like this in the repository.
The below query gives the distinct author from the post table.
#Query("select distinct author from Post")
List<String> findUniqueAuthor();
Write this in the repository
#Query(value = "Select Distinct * From (another select query)", nativeQuery = true)
List<Object> findUniqueData();

Using spring jdbc template to query for list of parameters

New to Spring JDBC template but I'm wondering if I am able to pass a list of parameters and execute query once for each parameter in list. As I've seen many examples, the list of parameters being passed is for the execution of the query using all the parameters provided. Rather I am trying to execute query multiple times and for each time using new parameter in list.
For example:
Let's say I have a List of Ids - params (Strings)
List<String> params = new ArrayList<String>();
params.add("1234");
params.add("2345");
trying to do something like:
getJdbcTemplate().query(sql, params, new CustomResultSetExtractor());
which I know as per documentation is not allowed. I mean for one it has to be an array. I've seen simple examples where query is something like "select * from employee where id = ?" and they are passing new Object[]{"1234"} into method. And I'm trying to avoid the IN() condition. In my case each id will return multiple rows which is why I'm using ResultSetExtractor.
I know one option would be to iterate over list and include each id in list as a parameter, something like:
for(String id : params){
getJdbcTemplate().query(sql, new Object[]{id}, new CustomResultSetExtractor());
}
Just want to know if I can do this some other way. Sorry, I Should mention that I am trying to do a Select. Originally was hoping to return a List of custom objects for each resultset.
You do need to pass an array of params for the API, but you may also assume that your first param is an array. I believe this should work:
String sql = "select * from employee where id in (:ids)"; // or should there be '?'
getJdbcTemplate().query(sql, new Object[]{params}, new CustomResultSetExtractor());
Or you could explicitly specify, that the parameter is an array
getJdbcTemplate().query(sql, new Object[]{params}, new int[]{java.sql.Types.ARRAY}, new CustomResultSetExtractor());
You can use preparedStatement and do batch job:
eg. from http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html
public int[] batchUpdate(final List<Actor> actors) {
int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, " +
"last_name = ? where id = ?",
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, actors.get(i).getFirstName());
ps.setString(2, actors.get(i).getLastName());
ps.setLong(3, actors.get(i).getId().longValue());
}
public int getBatchSize() {
return actors.size();
}
});
return updateCounts;
}
I know you don't want to use the in clause, but I think its the best solution for your problem.
If you use a for in this way, I think it's not optimal.
for(String id : params){
getJdbcTemplate().query(sql, new Object[]{id}, new CustomResultSetExtractor());
}
I think it's a better solution to use the in clause. And then use a ResultSetExtractor to iterate over the result data. Your extractor can return a Map instead of a List, actually a Map of List.
Map<Integer, List<MyObject>>
Here there is a simple tutorial explaining its use
http://pure-essence.net/2011/03/16/how-to-execute-in-sql-in-spring-jdbctemplate/
I think this is the best solution:
public List<TestUser> findUserByIds(int[] ids) {
String[] s = new String[ids.length];
Arrays.fill(s, "?");
String sql = StringUtils.join(s, ',');
return jdbcTemplate.query(String.format("select * from users where id in (%s)", sql),
ArrayUtils.toObject(ids), new BeanPropertyRowMapper<>(TestUser.class));
}
this one maybe what you want. BeanPropertyRowMapper is just for example, it will be very slow when there's a lot of records. you should change it to another more efficient RowMapper.

How to query data via Spring data JPA with user defined offset and limit (Range)

Is it possible to fetch data in user defined ranges [int starting record -int last record]?
In my case user will define in query String in which range he wants to fetch data.
I have tried something like this
Pageable pageable = new PageRequest(0, 10);
Page<Project> list = projectRepository.findAll(spec, pageable);
Where spec is my defined specification but unfortunately this do not help.
May be I am doing something wrong here.
I have seen other spring jpa provided methods but nothing are of much help.
user can enter something like this localhost:8080/Section/employee? range{"columnName":name,"from":6,"to":20}
So this says to fetch employee data and it will fetch the first 15 records (sorted by columnName ) does not matter as of now.
If you can suggest me something better that would be great.if you think I have not provided enough information please let me know, I will provide required information.
Update :I do not want to use native or Create query statements (until I don't have any other option).
May be something like this:
Pageable pageable = new PageRequest(0, 10);
Page<Project> list = projectRepository.findAll(spec, new pageable(int startIndex,int endIndex){
// here my logic.
});
If you have better options, you can suggest me that as well.
Thanks.
Your approach didn't work, because new PageRequest(0, 10); doens't do what you think. As stated in docs, the input arguments are page and size, not limit and offset.
As far as I know (and somebody correct me if I'm wrong), there is no "out of the box" support for what you need in default SrpingData repositories. But you can create custom implementation of Pagable, that will take limit/offset parameters. Here is basic example - Spring data Pageable and LIMIT/OFFSET
We can do this with Pagination and by setting the database table column name, value & row counts as below:
#Transactional(readOnly=true)
public List<String> queryEmployeeDetails(String columnName,String columnData, int startRecord, int endRecord) {
Query query = sessionFactory.getCurrentSession().createQuery(" from Employee emp where emp.col= :"+columnName);
query.setParameter(columnName, columnData);
query.setFirstResult(startRecord);
query.setMaxResults(endRecord);
List<String> list = (List<String>)query.list();
return list;
}
If I am understanding your problem correctly, you want your repository to allow user to
Provide criteria for query (through Specification)
Provide column to sort
Provide the range of result to retrieve.
If my understanding is correctly, then:
In order to achieve 1., you can make use of JpaSpecificationExecutor from Spring Data JPA, which allow you to pass in Specificiation for query.
Both 2 and 3 is achievable in JpaSpecificationExecutor by use of Pagable. Pageable allow you to provide the starting index, number of record, and sorting columns for your query. You will need to implement your range-based Pageable. PageRequest is a good reference on what you can implement (or you can extend it I believe).
So i got this working as one of the answer suggested ,i implemented my own Pageable and overrided getPagesize(),getOffset(),getSort() thats it.(In my case i did not need more)
public Range(int startIndex, int endIndex, String sortBy) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.sortBy = sortBy;
}
#Override
public int getPageSize() {
if (endIndex == 0)
return 0;
return endIndex - startIndex;
}
#Override
public int getOffset() {
// TODO Auto-generated method stub
return startIndex;
}
#Override
public Sort getSort() {
// TODO Auto-generated method stub
if (sortBy != null && !sortBy.equalsIgnoreCase(""))
return new Sort(Direction.ASC, sortBy);
else
return new Sort(Direction.ASC, "id");
}
where startIndex ,endIndex are starting and last index of record.
to access it :
repository.findAll(spec,new Range(0,20,"id");
There is no offset parameter you can simply pass. However there is a very simple solution for this:
int pageNumber = Math.floor(offset / limit) + ( offset % limit );
PageRequest pReq = PageRequest.of(pageNumber, limit);
The client just have to keep track on the offset instead of page number. By this I mean your controller would receive the offset instead of the page number.
Hope this helps!

how to select value and count in spring jpa?

i have table named gifts that contains field company_value_id and i want to make select for all company_value_id,count(company_value_id) so that the result will be list of object and each object will contain company_value_id,count(company_value_id)
i am using spring jpa with annotations as follows:
public interface GiftsRepository extends JpaRepository<Gifts, String> {
#Query("from Gifts g where g.companyGuid = :companyGuid")
List<Gifts> getGiftsByCompany(#Param("companyGuid") String companyGuid);
}
please advise, thanks.
i was able to accomplish it as follows:
#Query("select g.value.id,cr.value.name,count(g.value.id) from Gift g where g.user.id=:userId group by g.value")
List<Object[]> getUserGifts(
#Param("userId") String userId);
and in the service layer i extract the values as follows:
List<Object[]> results = giftsRepository
.getUserGifts(userId);
for (Object[] result : results) {
String id = (String) result[0];
String name = (String) result[1];
int count = ((Number) result[2]).intValue();
}
You need add a parameter to your function,just like this:
#Query("from Gifts g where g.companyGuid = :companyGuid")
List<Gifts> getGiftsByCompany(#Param("companyGuid") String companyGuid,Pageable pageable);
and the pageabel can be create like this:
Pageable pageable = new PageRequest(pageIndex, pageSize, Direction.ASC, sortColumn);

Using distinct in Spring data over multiple columns

My domain model is like this:
CollectedData {
String name;
String description;
int count;
int xAxis,
int yAxis
}
Using Spring data repository query, I would like to retrieve all the unique rows (unique with name, xAxis, yAxis)
I am trying something like this
#Query("select distinct a.name, a.xAxis, a.yAxis from CollectedData a")
List<CollectedData> findAllDistinctData();
So, when I do
List<CollectedData> records= findAllDistinctData();
for (CollectedData record : records) { //Exception on this line
}
Exception
[Ljava.lang.Object; cannot be cast to CollectedData.
Is there any other way to write query for this ?
#Query return ArrayList of Object(s) instead of specific type of object. so you have to define some thing like
#Query("select distinct a.name, a.xAxis, a.yAxis from CollectedData a")
List<Object> findAllDistinctData();
then cast according to your requirement,
List<Object> cdataList=findAllDistinctData();
for (Object cdata:cdataList) {
Object[] obj= (Object[]) cdata;
String name = (String)obj[0];
String description = (String)obj[1];;
...
}
Instead of returning an object you can use JPA's constructor expression feature to return a more specific object holding only the columns you're interested in. See also following answer:
JPQL Constructor Expression - org.hibernate.hql.ast.QuerySyntaxException:Table is not mapped
According to your example you could create a new Object with only the columns you are interested in:
SELECT DISTINCT new com.mypackage.MyInterestingCollectedData(a.name, a.xAxis, a.yAxis) from CollectedData a
If you want to select complete object based on distinct values of multiple columns,
In that case the native query would be the option.
e.g.
#Query(
value = "select distinct on (column1, column2, column3) * From my_table where someId=: order by column1 asc,column2 desc,column3 desc,column4 desc",
nativeQuery = true
)
fun finalAllDistinctBy(containerId: String): List<MyTable>

Resources