I have a some questions about Spring rowmapper. I'm going to receive data from my DB using rowmapper.But my command object 'Table' only have List variable.
is Rowmapper automatically map each record to List ? is it posibble?
i know spring bind tag is automatically bind value to list.
right this.
Table.java
public class Table implements Serializable{
private List<String> tableNum = new ArrayList<String>();
// setter and getter
}
Dao
private class TableRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Table table = new Table();
table.setTableNum(rs.getString("TABLE_LOCATION"));
return table;
}
}
The RowMapper is used to map a single row to a single domain object, not a bunch of rows results to a single domain object. Also the RowMapper isn't a Dao type object. It is to be used with some query method, like JdbcTemplate.query(sql,args,rowMapper)
But in your case, you don't want a RowMapper. You should instead just use a JdbcTemplate.queryForList. See the JdbcTemplate API for more query method. A simple example would be something like:
public class YourDaoImpl extends JdbcTemplate implements YourDao {
private static final String SQL =
"select SOME_FIELD from SOME_TABLE where SOMETHING = ?";
#Override
public List<String> getSomeFieldBySomething(String something) {
return (List<String>)queryForList( SQL,
new Object[] { something },
String.class);
}
}
You use the dao for your services.
UPDATE
Because of your help, I can get a one column from my DB. but I got a problems. my db table is made of multiple columns. and i must receive all of them. and.. how can i do it? plz help me~!!!
You posted question in no points that out. In this case you need to make a List<DomainObject>. Not a List<String>. List<String> only allows for one value. If you have a List<DomainObject>, then the class DomainObject can have all your fields. Then that's when you use the RowMapper. And you can still use queryForList that uses the RowMapper variant
public class Table {
private String field1;
private String field2;
private String field3;
// getters and setters
}
public class YourDaoImpl extends JdbcTemplate implements YourDao {
private static final String SQL =
"select * from SOME_TABLE where SOMETHING = ?";
#Override
public List<Table> getTableBySomething(String something) {
return (List<Table>)queryForList( SQL,
new Object[] { something },
new RowMapper<Table>(){
#Override
public Table mapRow(ResultSet rs, int rowNumber) {
Table table = new Table();
table.setField1(rs.getString("feild1"));
// set the others
return table;
}
});
}
}
An aside, if I were you, I would forget the jdbc and go for an ORM framework like JPA. If you want entire domain objects, this is the way to go.
Related
I'm trying to update automaticly all entries of a new sql column with the #PostPersist anotation.
the model :
int id;
String firstName;
String SecondName;
String Maths;
#AutoWired
ModelService modelService;
#PostPersist
public void setMathsWithPostPersist(){
if(Maths == null) {
Maths = modelService.calculate(id);
}
}
Then, here's the service:
public int calculateById(int id){
Model model = modelRepository.getById(id);
int number = calculateNumber(model);
model.setMaths(number);
modelRepository.save(organisme);
return number;
}
I don't know if it's due to the fact that I'm using an autowired in the model class, that's my first use of #PostPersist.
What did I do wrong?
The #PostPersist listener is only invoked when "persisting" an entity, but what you are doing here is an update of an existing entity, so you would have to use #PostUpdate instead.
#Entity
public class A{
//some properties
}
#Entity
public class B{
//Some properties
}
I want to fetch selected columns from two tables using JPA, I know how to fetch single Entity table data through Repository and Controllers.
Repository:
public interface extends JPARepository<A, Long>{
List<A> findAll();}
Controller:
public class class_name{
#AutoWired
private JPARepository repo;
#RequestMapping("/data")
public List<A> getData(){
return repo.findAll();
}
}
Above code is to fetch single table data. Now, I want to fetch selected columns from both the tables.
Note: A, B Entities have mappings
What you can do is to use #Query annotation on one of your methods in the repository and performs something like this:
public Name {
String firstName;
String telephone;
public Name(String firstName,String telephon) {
//initialize fields
}
}
#Query(select new dummy.Name(u.name,c.telephone) from User u join fetch u.contact c where u.externalId= ?1 )
public Name getName(String externalId){}
You can return easily List instead of using constructor query , but i find it cleaner this way.
Model
#Column(name="Desc", name="des", name="DS")
private String description;
How can I mention multiple name of column ? so, that if any one found it map value to description?
How can I mention multiple name of column ?
You can't. A database does not allow columns to have multiple names, hence you can't map multiple column names to a class field.
so, that if any one found it map value to description?
If you have multiple stored procedures that return in their respective result set "Desc", "des", "ds" and you need to map this to the same Java class - you need to define different row mappers and describe the mapping there.
For example let's say you have SP1 and SP2 and you want both result sets from those to be mapped to ResultDto.
ResultDto looks like:
public class ResultDto {
private String name; //always maps to DB column "name"
private String desc; //maps to different DB columns - "ds", "desc"
//ommitted..
}
You can define a base row mapper and define the mapping for all overlapping fields of all Stored Procs result sets.
Code Example:
protected static abstract class BaseRowMapper implements RowMapper<ResultDto> {
public abstract ResultDto mapRow(ResultSet rs, int rowNum) throws SQLException;
protected void mapBase(ResultSet rs, ResultDto resultDto) throws SQLException {
resultDto.setName(rs.getString("name")); //map all overlapping fields/columns here
}
}
private static class SP1RowMapper extends BaseRowMapper {
#Override
public ResultDto mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultDto resultDto = new ResultDto();
mapBase(rs, resultDto);
resultDto.setDescription(rs.getString("ds"));
return resultDto;
}
}
private static class SP2RowMapper extends BaseRowMapper {
#Override
public ResultDto mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultDto resultDto = new ResultDto();
mapBase(rs, resultDto);
resultDto.setDescription(rs.getString("desc"));
return resultDto;
}
}
I don't know how you call the Stored Procedures, but if you use Spring's SimpleJdbcCall, the code will look like:
new SimpleJdbcCall(datasource)
.withProcedureName("SP NAME")
.declareParameters(
//Stored Proc params
)
.returningResultSet("result set id", rowMapperInstance);
so i basically want to process a HTTP-Post with a Controller in Spring and send back a result for the User AND after that i want to make a database call.
So here is my example:
#Controller
public class AngebotController extends WebMvcConfigurerAdapter {
#Autowired
private DatabaseUtils dbUtil;
#Autowired
private MyMailSender mailSender;
#RequestMapping(value = REQUEST_PATH, method = RequestMethod.POST)
public String doPost(#Valid FormInput input, BindingResult bindingResult) {
// .. some input validations here
// after the validation is complete i will have accesss to a object, that i just created, just like the following
// Lets say that this object holds important values for the database query
final MyObject validatedInput = new MyObject();
// Start a new Thread to do the remaining work (the Database Call)
Thread t = new Thread() {
#Override
public void run() {
// so i am starting the database query with the information that i just validated above
// That Database Query will Return a List of Items based on the given MyObject
// This Query will take a long time and i dont want the user to wait, because this data is not nessessary for the user
List<Item> items = dbUtil.getStuffByInput(validatedInput);
for(Item i : items) {
// Now i just want to send some informations about the item via email, this part works
mailSender.sendMail("mail#mail.mail", i);
}
}
}.start();
return "viewname";
}
}
#Service
public class DatabaseUtils {
#Autowired
private ItemRepository repository;
public List<Item> getStuffByInput(MyObject o) {
List<Item> items = repository.findAllByMyObject(o);
// Doing some more stuff with those items here ..
return items;
}
}
// The Implementation will be generated by Spring
public interface ItemRepository extends CrudRepository<Item, Long> {
// will select all Items by comparing the myObject with each Item
// This also works like intended
public List<Item> findAllByMyObject(MyObject myObject);
}
So where is my Problem?
The only Problem i have is, that the Database Query will end throwing an Exception, because the Database Connection was closed (i guess by Spring)
The Exception: Exception in thread "Thread-6" org.hibernate.SessionException: Session is closed!
Any Help appreciated.
Thanks!
I'm using spring mvc and I created the CRUD functionality. But I want to create a search function that will allow me to find a user by any parameter (variable) as 'userid' or 'username' or 'lastname' or 'social security number' or whatever.
My userid is an integer type.
How can I do that? What is the SQL query for that?
How can I check if the input is integer or string and then go through the database by the given parameter and search for the user?
If you are using Hibernate for data access you can easily create universal finder using criteria API:
Abstract DAO class:
public abstract class AbstractHibernateDAO<T> {
private static final String PARAM_VALUE_PARAMETER = "paramValue";
private final Class<T> clazz;
#Autowired
private SessionFactory sessionFactory;
public AbstractHibernateDAO(Class<T> clazz) {
this.clazz = clazz;
}
public T findOne(String paramName, Object paramValue) {
Session session = sessionFactory.getCurrentSession();
#SuppressWarnings("unchecked")
T fetchedObject = (T) session.createCriteria(clazz).add(Restrictions.eq(paramName, paramValue)).uniqueResult();
return fetchedObject;
}
// Other CRUD methods.
}
Concrete DAO class for entity:
#Repository
#Transactional
public class ProductHibernateDAO extends AbstractHibernateDAO<Product> {
public ProductHibernateDAO() {
super(Product.class);
}
}
Or if you prefer to use HQL instead of Criteria API you can rewrite search method as:
public T findOne(String paramName, Object paramValue) {
Session session = sessionFactory.getCurrentSession();
StringBuilder queryText = new StringBuilder();
queryText.append("from ");
queryText.append(clazz.getSimpleName());
queryText.append(" where ");
queryText.append(paramName);
queryText.append("=:");
queryText.append(PARAM_VALUE_PARAMETER);
#SuppressWarnings("unchecked")
T fetchedObject = (T) session.createQuery(queryText.toString()).setParameter(PARAM_VALUE_PARAMETER, paramValue).uniqueResult();
return fetchedObject;
}
In this article you can find very good description how to create generic DAO with hibernate (Or if you prefer JPA there are also described how to do this with JPA).
Or if you prefer to use JDBC for data access I recommend you to look at Spring's JdbcTemplate. It simplifies development a lot. Here how you can implement universal finder using JdbcTemplate:
#Repository
#Transactional
public class ProductJDBCDAO implements DAO<Product> {
private static final String TABLE_NAME = "product";
#Autowired
private JdbcTemplate jdbcTemplate;
public Product findOne(String paramName, Object paramValue) {
RowMapper<Product> rowMapper = new RowMapper<Product>(){
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
long productId = rs.getLong("product_id");
// Other properties
Product product = new Product(...);
return product;
}
};
StringBuilder queryText = new StringBuilder();
queryText.append("select * from ");
queryText.append(TABLE_NAME);
queryText.append(" where ");
queryText.append(paramName);
queryText.append("=?");
Product fetchedObject = jdbcTemplate.queryForObject(queryText.toString(), rowMapper, paramValue);
return fetchedObject;
}
// Other CRUD methods
}
Ass you can see in all examples you don't need explicitly specify parameter type, you just add it as Object parameter.
If you will work with direct JDBC in such case I recommend you to use PreparedStatement and it's setObject(..) method. Query text will be similar to shown in the example with JdbcTemplate.