How to load data from JDBCTemplate.queryForMap() and it returns the Map Interface.How the maintained the query data internally in map.I trying to load but i got below exception i.e., org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result
Code:-
public List getUserInfoByAlll() {
List profilelist=new ArrayList();
Map m=new HashMap();
m=this.jdbctemplate.queryForMap("SELECT userid,username FROM USER");
Set s=m.keySet();
Iterator it=s.iterator();
while(it.hasNext()){
String its=(String)it.next();
Object ob=(Object)m.get(its);
log.info("UserDAOImpl::getUserListSize()"+ob);
}
return profilelist;
}
Plz help me
queryForMap is appropriate if you want to get a single row. You are selecting without a where clause, so you probably want to queryForList. The error is probably indicative of the fact that queryForMap wants one row, but you query is retrieving many rows.
Check out the docs. There is a queryForList that takes just sql; the return type is a
List<Map<String,Object>>.
So once you have the results, you can do what you are doing. I would do something like
List results = template.queryForList(sql);
for (Map m : results){
m.get('userid');
m.get('username');
}
I'll let you fill in the details, but I would not iterate over keys in this case. I like to explicit about what I am expecting.
If you have a User object, and you actually want to load User instances, you can use the queryForList that takes sql and a class type
queryForList(String sql, Class<T> elementType)
(wow Spring has changed a lot since I left Javaland.)
I know this is really old, but this is the simplest way to query for Map.
Simply implement the ResultSetExtractor interface to define what type you want to return. Below is an example of how to use this. You'll be mapping it manually, but for a simple map, it should be straightforward.
jdbcTemplate.query("select string1,string2 from table where x=1", new ResultSetExtractor<Map>(){
#Override
public Map extractData(ResultSet rs) throws SQLException,DataAccessException {
HashMap<String,String> mapRet= new HashMap<String,String>();
while(rs.next()){
mapRet.put(rs.getString("string1"),rs.getString("string2"));
}
return mapRet;
}
});
This will give you a return type of Map that has multiple rows (however many your query returned) and not a list of Maps. You can view the ResultSetExtractor docs here: http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/jdbc/core/ResultSetExtractor.html
To add to #BrianBeech's answer, this is even more trimmed down in java 8:
jdbcTemplate.query("select string1,string2 from table where x=1", (ResultSet rs) -> {
HashMap<String,String> results = new HashMap<>();
while (rs.next()) {
results.put(rs.getString("string1"), rs.getString("string2"));
}
return results;
});
You can do something like this.
List<Map<String, Object>> mapList = jdbctemplate.queryForList(query));
return mapList.stream().collect(Collectors.toMap(k -> (Long) k.get("userid"), k -> (String) k.get("username")));
Output:
{
1: "abc",
2: "def",
3: "ghi"
}
Related
Hello so I am trying to get list of IDs from mongoDB , wrote this code that returns map of id:value I just want it to return just values .
query=new Query(Criteria.where("_id").is("47b3b1ab-2d80-42cf-b289-e3d45497b59f"));
query.fields().include("recordList.id").exclude("_id");
System.out.println( mongoTemplate.findOne(query, Map.class,"Company3"));
{recordList=[{id=rec4vCGPy3EnXRuCM}, {id=recAivYlqtDzZP62C}, {id=recbcLfxuLLB6Jjn0}, {id=reckIA8RdQtDUKCYI}, {id=rectnZZzBJ2iKN8eO}]}
But I need something like this
[rec4vCGPy3EnXRuCM, recAivYlqtDzZP62C, recbcLfxuLLB6Jjn0, reckIA8RdQtDUKCYI, rectnZZzBJ2iKN8eO]
Yes I know I can manipulate result like this to get desired result but I want to know if its possible to achieve same result directly from DB and not like this
List<Map<String,String>> list = (List<Map<String, String>>) mongoTemplate.findOne(query, Map.class,"Company3").get("recordList");
List<String> idList=new ArrayList<>();
for (Map<String, String> stringStringMap : list) {
idList.add(stringStringMap.get("id"));
}
This is what my data looks like
mongodb document. Sorry for inserting image , couldnt copy it without it being unreadable .
oblivion02's solution was a little bit wrong but definitely hinted me in right direction , thank you.
Query query=new Query(Criteria.where("_id").is("adfe377d-6e5b-48f0-b5bb-12b09f57285d"));
System.out.println(mongoTemplate.findDistinct(query,"recordList.id","Company4",String.class));
Just these two lines give me a nice clean list of just id values
[rec4vCGPy3EnXRuCM, recAivYlqtDzZP62C, recbcLfxuLLB6Jjn0, reckIA8RdQtDUKCYI]
Maybe distinct could help. https://docs.mongodb.com/manual/reference/method/db.collection.distinct/
Query query=new Query(Criteria.where("_id").is("adfe377d-6e5b-48f0-b5bb-12b09f57285d"));
System.out.println(mongoTemplate.findDistinct(query,"recordList.id","Company4",String.class));
You can not do that using Mongodb. This database is document oriented, meaning that given a criteria (in this case, an id), you will get a list of documents satifying the criteria where each document has some properties and some values.
To make it easier, you could rewrite your code so you could map your result to a pojo which only contains the list of ids you want and no key.
It would be something similar to the following:
public class Result {
private List<String> ids;
// getters and setters here
#override
public String toString(){
return ids.toString();
}
}
Now your repository method retrieving data will look like the following:
query = new Query(Criteria.where("_id").is("47b3b1ab-2d80-42cf-b289-e3d45497b59f"));
// No need for this
//query.fields().include("recordList.id").exclude("_id");
System.out.println( mongoTemplate.findOne(query, Result.class,"Company3"));
I am using below bean definition to configure a reader to read some data from the database table in a Spring Batch project. It is using a named param in SQL. I am passing A java.util.List as a parameter. However, I am getting Invalid Column type error when it tries to run the SQL.
If I just hard code one single value (namedParameters.put("keys", "138219"); ) instead of passing a list, it works.
#Bean
public JdbcCursorItemReader<MyDTO> myReader() {
JdbcCursorItemReader<MyDTO> itemReader = new JdbcCursorItemReader<>();
itemReader.setDataSource(myDatasource);
itemReader.setRowMapper(return new RowMapper<MyDTO>() {
#Override
public MyDTO mapRow(ResultSet resultSet, int rowNum) throws SQLException {
return toMyDto(resultSet);
}
};);
Map<String, Object> namedParameters = new HashMap<>();
List<Long> keys= //Some List
Map<String, List<Long>> singletonMap = Collections.singletonMap("keys", keys);
namedParameters.putAll(singletonMap);
itemReader.setSql(NamedParameterUtils.substituteNamedParameters("SELECT A FROM MYTABLE WHERE KEY IN (:keys)",new MapSqlParameterSource(namedParameters)));
ListPreparedStatementSetter listPreparedStatementSetter = new ListPreparedStatementSetter();
listPreparedStatementSetter.setParameters(
Arrays.asList(NamedParameterUtils.buildValueArray("SELECT A FROM MYTABLE WHERE KEY IN (:keys)", namedParameters)));
itemReader.setPreparedStatementSetter(listPreparedStatementSetter);
return itemReader;
}
I referred sample code snippet here as a response to one of the questions asked - it is what seems to be working when we pass one value. However, my issue is with passing a list instead of one value in the param. This is where it seems to fail.
The ListPreparedStatementSetter is not aware of parameters types. If a parameter is an array or a collection, it will set it as is to the first placeholder, leaving other placeholders unset. Hence the error. In your example, if List<Long> keys = Arrays.asList(1, 2), your sql statement will be:
SELECT A FROM MYTABLE WHERE KEY IN (?, ?)
If you pass your singletonMap to the ListPreparedStatementSetter, it will set the value of keys (which is of type List) to the first placeholder and that's it. The second placeholder will still be unset and the preparation of the statement will fail.
You can flatten parameters before passing them to the ListPreparedStatementSetter and it should work fine. I added a sample with how to flatten parameters before passing them to the prepared statement setter here (See flatten method).
Hope this helps.
I want to fetch large datasets from a MySql database, and return it as a List of comma separated Strings via a Webservice (not via a downloadable file, but directly as text).
Therefore I first need all selected rows in CSV format.
Question: What's the best way achieving this with Spring?
The following works with JdbcTemplate, but I don't know if this is the best approach (maybe optimize using Java 8 streams)?
Also if somehow feels wrong having to iterate the ResultSet and call rs.getString(i), concatenating each element of the ResultSet. Isn't there a more elegant way?
RowMapper<String> rowMapper = new RowMapper<String>() {
#Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
sb.append(rs.getString(i)).append(",");
}
return sb.toString();
}
};
String sql = "SELECT * from mypersons where age > 12";
List<String> list = new JdbcTemplate(dataSource).query(sql, params, rowMapper);
//...return the list via Webservice
Sidenote: I have to use native SQL for the select. They are much more complicated in my example above.
I recommend using Spring Data JPA to get a SET of persons. Once you have a set of persons, you can use streams to map the persons to the field you want to collect, and join that field with commas.
Assuming a Set, given a person has an attribute called name, this method will return a comma separated list of names.
public String joinName(Set<Person> persons) {
return persons.stream().map(Person::getName).collect(Collectors.joining(", "));
}
Your solution looks fine. I just have two possible improvements:
the indexed based access to the ResultSet already exists in the ColumnMapRowMapper. You could delegate to it and would get (pseudocode)
class CommaSeparatedStringRowMapper implements RowMapper<String> {
ColumnMapRowMapper delegate = new ColumnMapRowMapper();
#Override
public Map<String, Object> mapRow(ResultSet rs, int rowNum){
delegate.mapRow(rs, rowNum).valueSet().toStream.collect(Collectors)
}
Note: this will be less efficient, due to creating and accessing the intermediate map, but it looks nicer.
Note 2: The underlying map should preserve the order of columns, but you better double check.
Alternatively, you might consider using a RowCallbackHandler writing your results directly into a Webservice response thingy. If done right, part of your response might be on the way to your client while you are still processing the rest of the query result. So this might improve latency and memory consumption.
I am trying to add FullTextFilters to my FullTextQuery in hibernate and there is only the method FullTextFilter.setParameter(String name, Object value)
I am trying to make a flexible, generic function to add filters to the query based on the entity its searching for, some have one parameter, some have two for their filters, so I would like to add a method to FullTextFilterImpl; setParameters(String[] names, String[] value) where I can pass in the names of all the parameters and probably a multidimensional array of the values for each parameter to transform my current code of
If( "checking which entity it is"){
fullTextQuery.enableFullTextFilter("FilterName").setParameter("firstFilter", "val1").setParameter("secondFilter", "val2");
}
else if("this entity's filter only has one parameter"){
fullTextQuery.enableFullTextFilter("FilterName").setParameter("firstFilter", "val1");
}
I tried creating a subclass of FullTextFilterImpl and putting a setParameters function in it, but the way this code is set up I'm not sure how to utilize it as FullTextQuery.enableFullTextFilter(filterName) returns a FullTextFilter object and then you call the setParameter() on that object. I'm not sure how I would get in the middle of that to do a setParameters
EDIT: I have downloaded the hibernate-search source code and added the following method to FullTextFilterImpl which I think will do what I want, but when I go to build it (even just the out-of-the-box project) I get all these checkstyle Only one new line is allowed at the end of a file errors. Is there something I'm missing from the hibernate quick-build guide.
public FullTextFilter setParameters(Map<String, List<String>> params){
for (String key : params.keySet()) {
List<String> values = params.get(key);
for(int i=0; i< values.size() ; i++){
parameters.put(key, values.get(i));
}
}
return this;
}
You can easily pass a Map of attributes to your custom Filter, the signature is:
FullTextFilter setParameter(String name, Object value);
so you could do
filter.setParameter( "myMap", properties );
where properties is an hashmap.
About the compilation error message:
Only one new line is allowed at the end of a file
is a message from checkstyle, it verifies code style is conforming to the Hibernate code style.
It's very simple to fix: there are multiple empty lines at the end of the source file, delete them. The error message should tell you what file needs to be polished.
if i correctly understand you question you need Builder pattern
here an example you could use :
public class FullTextFilter {
String[] keys;
Object[] objects;
private FullTextFilter(String[] keys, Object[] objects) {
}
public static FullTextFilterBuilder builder(){
return new FullTextFilterBuilder();
}
public static class FullTextFilterBuilder {
private Map<String, Object> parameters = new HashMap<String, Object>();
public FullTextFilterBuilder setParameter(String key, Object value){
parameters.put(key, value);
return this;
}
public FullTextFilter build(){
return new FullTextFilter(parameters.keySet().toArray(new String[0]), parameters.values().toArray(new Object[0]));
}
}
}
and then using it like this :
FullTextFilter filter = FullTextFilter.builder().setParameter("", new Object()).setParameter("", new Object()).build();
tell if that's what you are looking for.
if not i'll delete my answer
I presume you want this:
fullTextQuery.enableFullTextFilter("FilterName").setParameter("firstFilter", "val1").setParameter("secondFilter", "val2");
fullTextQuery{
name:"FilterName"
,parameters:["filter1":"value1", "filter2":"value2"]
}
static FullTextQuery enableFullTextFilter(String name){...}
FullTextQuery setParameter(String key, String value){
parameters.put(key, value);
return this;
}
assuming a parameters hashmap.
seeing as I was a little off base.. cant you do something like this?
setFilters (HashMap<String, String> filters) {
FullTTextFilter fl = FullTextQuery.enableFullTextFilter("filtername");
for (String key : filters.keySet()) {
fl.setParameter(key, filters.get(key));
}
}
I'm trying to query for a set and return it as a hash map object with Spring JdbcTemplate. But some reasons I'm getting empty result set from server. It is possible that I have a problem in the overall configuration but the rest of the queries are working without problems.
This is how I query
public Map<Integer, String> getCompanyDataservers() {
return getTemplate().queryForObject("select id, dataserver from company", new RowMapper<Map<Integer,String>>() {
#Override
public Map<Integer, String> mapRow(ResultSet rs, int rowNum)
throws SQLException {
HashMap<Integer, String> toReturn = new HashMap<Integer, String>();
while(rs.next()) {
int id = rs.getInt("id");
toReturn.put(id, dataserver);
}
return toReturn;
}});
}
After some debugging and logging statements I concluded that my resultset seems to be empty of any rows. When I query the same ("select id, dataserver from company") manually directly from DB I get the desired result. Yet this way I get a resultset with 0 rows.
One of my theories is that can't get get this kind of set when querying for a object this way. But isn't there a possibility to be free at you queries and construct a more elaborate object as a query result, or I have to create a purpose built class to be used by "queryForList" to get the desired data and convert it afterwards?
Or am I just missing something?
You are not supposed to invoke rs.next() inside mapRow. JdbcTemplate will invoke mapRow for you for every row in the resultset
All you need to do on mapRow is just return a HashMap which represent one single database row, spring will do the resultset iteration for you