JdbcDaoSupport with a SQL SELECT FROM INSERT - java

I am trying to create a "select from insert" within my Spring JdbcDaoSupport class and am having trouble figuring out how to get the data from the select statement and return it.
My EventJdbcTemplate (my DaoImpl):
#Service
public class EventJdbcTemplate extends JdbcDaoSupport implements EventDao {
private static final Logger LOGGER = Logger.getLogger(EventJdbcTemplate.class);
private static final String SQL_INSERT_EVENT = "SELECT EVENT_ID FROM FINAL TABLE " +
"(INSERT INTO EBT10DBB.SB0401T0 (EVENT_NAME, HOST_NAME, USER_ID) " +
"VALUES(?, ?, \'EMP0321\'))";
#Autowired
public EventJdbcTemplate(DataSource pDataSource) {
super.setDataSource(pDataSource);
}
#Override
public Integer createEvent(EventBean pEventBean) { //(Integer id, String eventName)
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Entering create(Event event) of EventJDBCTemplate.");
}
// This SQL works, but is for an INSERT only.
/*this.getJdbcTemplate().query(SQL_INSERT_EVENT, new Object[]{
pEventBean.getEventName(),
pEventBean.getHostName()
});*/
final List eventList = this.getJdbcTemplate().query(SQL_INSERT_EVENT, new Object[]{
pEventBean.getEventName(),
pEventBean.getHostName()
}, new EventRowMapper()
);
Event event = null;
for (int i = 0; i < eventList.size(); i++) {
event = (Event)eventList.get(i);
}
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Exiting create(Event event) of EventJDBCTemplate.");
}
//return statement -- should return either the entire "pEventBean", or
//just the unique key, "EVENT_ID".
return event.getId();
}
EventRowMapper class (Not sure is I'll need this for the select or not):
public class EventRowMapper implements RowMapper<Event> {
#Override
public Event mapRow(ResultSet rs, int rowNum) throws SQLException {
final EventBuilder event = new EventImpl.EventBuilder();
event.setId(rs.getInt("EVENT_ID"));
event.setEventName("EVENT_NAME");
event.setHostName("HOST_NAME");
return event.build();
}
}
So my goal is to return an Integer value that would be the unique key (EVENT_ID) that is created from the INSERT SQL.

You can use SimpleJdbcInsert provided by Spring to get back generated keys, see following documentation provided by Spring section
13.5.2 Retrieving auto-generated keys using SimpleJdbcInsert
Here is the Link

Related

DAO design pattern: where should the database access be implemented?

I am building a Java application that uses a database and I'm using a DAO design pattern: in my code, all objects classes have an associated DAO class that implements an interface with get, save and update methods.
For instance, for a User object, I will have the following class (ConnectionDB implements the connection to the database):
public class UserDAO implements Dao<User, String> {
private final static String TABLE_NAME = "users";
private final static UserDAO instance = new UserDAO();
public static UserDAO getInstance() {
return instance;
}
private UserDAO() {
}
#Override
public User get(String username) throws SQLException {
String query = "SELECT * FROM " + TABLE_NAME + " WHERE username = ?";
PreparedStatement stmt = ConnectionDB.getInstance().prepareStatement(query);
stmt.setString(1, username);
ResultSet result = stmt.executeQuery();
if (!result.next())
return null;
User user = new User(
result.getInt("id"),
username,
);
stmt.close();
result.close();
return user;
}
/* same thing for save and update */
}
Here is the Dao interface for reference:
public interface Dao<T, S> {
T get(S id) throws SQLException;
ArrayList<T> getAll() throws SQLException;
void save(T t) throws SQLException;
void update(T t) throws SQLException;
}
This way works pretty fine but as I have more and more classes in my application, and a DAO class for each one of them, I have a lot of repetitive code. For instance, the only difference between the get implementation on different objects is the name and type of the primary key and the call to the constructor.
In order to make the code more generic, I tried to implement a fetchItem method in the ConnectionDB class that would be able to query an item from the database:
public <T> HashMap<String, Object> fetchItem(String table_name, String pk, T id) throws SQLException {
String query = "SELECT * FROM " + table_name + " WHERE " + pk + " = ?";
PreparedStatement stmt = prepareStatement(query);
stmt.setObject(1, id);
ResultSet result = stmt.executeQuery();
if (!result.next())
return null;
HashMap<String, Object> values = buildObject(result);
stmt.close();
result.close();
return values;
}
public HashMap<String, Object> buildObject(ResultSet result) throws SQLException {
ResultSetMetaData metadata = result.getMetaData();
int columnCount = metadata.getColumnCount();
HashMap<String, Object> values = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
values.put(metadata.getColumnName(i), result.getObject(i));
}
return values;
}
With this implementation, I can now replace my first get method in the UserDAO class by the following simplified code:
public User get(String username) throws SQLException {
HashMap<String, Object> values = ConnectionDB.getInstance()
.fetchItem(TABLE_NAME, "username", username);
if (values == null || values.isEmpty())
return null;
return new User(
id,
(String) values.get("String")
);
}
While this new implementation is simpler and allows the get methods to only do what they're supposed to do (here, create a User object with the right parameters from the DB), I find it a bit dangerous as I'll have to make a lot of casts; as I have a lot of Object variables in my code I'm not sure whether it'll be easy to debug the code if something fails in any of these function calls.
So here's my question: which implementation is better, easier to maintain and safer?
Connection DB is a very bad place to define such implementation. It is just a link with a specific database thats all. You violate single responsibility rule. Better to implement base generic class for all DAO's and place common logic there.
Also if you will use Hibernate framework, you will not need to work with query strings and Object variables casts.

Do I have to create another RowMapper?

I'm developing this application to fetch data from a single table from an existing Oracle database.
Here we've got the entity:
public class OrdemDeServicoCount {
private Long ordensInternas;
private Long ordensAtrasadas;
// assume getters and setters
}
The mapper:
public class OrdemMapper implements RowMapper<OrdemDeServicoCount> {
#Override
public OrdemDeServicoCount mapRow(ResultSet rs, int rowNum) throws SQLException {
OrdemDeServicoCount ordens = new OrdemDeServicoCount();
ordens.setOrdensInternas(rs.getLong("ordensInternas"));
// ordens.setOrdensAtrasadas(rs.getLong("ordensAtrasadas"));
return ordens;
}
}
And finally, the DAO:
public class OrdemDAO {
private JdbcTemplate jdbcTemplate;
public OrdemDAO(JdbcTemplate jdbcTemplate) {
super();
this.jdbcTemplate = jdbcTemplate;
}
public List<OrdemDeServicoCount> countOrdensInternasSemEncerrar() {
String sql = "SELECT COUNT(a.nr_sequencia) AS ordensInternas FROM MAN_ORDEM_SERVICO a "
+ "WHERE a.IE_STATUS_ORDEM IN (1,2) AND a.NR_GRUPO_PLANEJ IN (21)";
List<OrdemDeServicoCount> ordens = jdbcTemplate.query(sql, new OrdemMapper());
return ordens;
}
By the way, you all must know that if I declare uncomment the line ordens.setOrdensInternas(rs.getLong("ordensInternas")); in the mapper, I would get an error, because in my DAO, I'm not using that field.
But what if I need to create another method that uses just the ordensInternas field? Then again, I'd get an error...
So, my doubt here is: if I need to use the ordensAtrasadas field from the entity, will I have to create another class just to implement another mapper? Or is there a way that I can do any conditional in my current OrdemMapper class?
Just put your assignments in individual try-catch statements.
public class OrdemMapper implements RowMapper<OrdemDeServicoCount> {
#Override
public OrdemDeServicoCount mapRow(ResultSet rs, int rowNum) throws SQLException {
OrdemDeServicoCount ordens = new OrdemDeServicoCount();
try {
ordens.setOrdensInternas(rs.getLong("ordensInternas"));
} catch (SQLException ex) {
// This will happen if the columnIndex is invalid among other things
}
try {
ordens.setOrdensAtrasadas(rs.getLong("ordensAtrasadas"));
} catch (SQLException ex) {
// This will happen if the columnIndex is invalid among other things
}
return ordens;
}
}

What is wrong with this lambda syntax (Java)?

Just so I don't forget
Java 8 SE
Eclipse 2019-12
Spring Boot 2.2.4.RELEASE
I am trying to learn Spring Boot, and I am struggling to understand why a lambda doesn't compile. Here is the spring boot example (which compiles).
jdbcTemplate.query(
"SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[] { "Josh" },
(rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name"))
).forEach(customer -> log.info(customer.toString()));
And here is my attempt to modify this example to my own needs:
#RestController
public class SwitchController {
#Autowired
JdbcTemplate jdbcTemplate;
#GetMapping
public Rows getSwitchRows() {
Rows switches = new Rows();
jdbcTemplate.query(
"SELECT swityp, oldkey, newkey, delete FROM table",
(rs, rowNum) -> new Switch(rs.getString("swityp"), rs.getString("oldkey"), rs.getString("newKey"), rs.getString("delete"))
).forEach(switch -> switches.addRow(switch));
return switches;
}
}
The lambda in the forEach() gives an error on -> which says Syntax error on token "->", ( expected and also on switches.addRow(switch) which says Syntax error on token "switch", delete this token. It is almost as if the forEach() doesn't recognize that I typed a lambda. Maybe what I thought was a lambda, isn't. If that is the case, what makes it not a lambda?
Here are my Switch and Rows classses in case that helps:
Switch.java
public class Switch {
private final String switchType;
private final String oldKey;
private final String newKey;
private final String delete;
public Switch(String switchType, String oldKey, String newKey, String delete) {
this.switchType = switchType;
this.oldKey = oldKey;
this.newKey = newKey;
this.delete = delete;
}
public String getSwitchType() {
return switchType;
}
public String getOldKey() {
return oldKey;
}
public String getNewKey() {
return newKey;
}
public String getDelete() {
return delete;
}
}
Rows.java
public class Rows {
private Object[] rows;
public Rows () {
super();
}
public void addRow (Object row) {
rows[rows.length] = row;
}
}

Sorting with SortableDataProvider and Hibernate

I have the following code:
PersonDao.java
#Repository
#Transactional
public class PersonDao implements PersonDaoIface {
Object property;
String order;
#Autowired
private SessionFactory sessionFactory;
public PersonDao() {
}
public PersonDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#SuppressWarnings("unchecked")
#Override
public List<Person> getAll(long first, long count) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
this.setPaging(criteria, first, count);
addSort(criteria);
return criteria.list();
}
#Override
public long getAllCount() {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class)
.setProjection(Projections.rowCount());
Long i = (Long) criteria.uniqueResult();
return i;
}
#Override
public List<Person> getByFilter(Person person, int first, int count) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
criteria.add(Restrictions.eq("firstName", person.getFirstName()));
criteria.add(Restrictions.eq("lastName", person.getLastName()));
this.setPaging(criteria, first, count);
return criteria.list();
}
#Override
public long getByFilterCount(Person person) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
criteria.add(Restrictions.eq("firstName", person.getFirstName()));
criteria.add(Restrictions.eq("lastName", person.getLastName()));
criteria.setProjection(Projections.rowCount());
Long result = (Long) criteria.uniqueResult();
return result;
}
private void setPaging(Criteria criteria, long first, long count) {
criteria.setFirstResult((int) first);
criteria.setMaxResults((int) count);
}
private void addSort(Criteria criteria) {
if (property != null) {
if (order.equalsIgnoreCase(SortOrder.ASCENDING.toString())) {
criteria.addOrder(Order.asc((String)property));
} else {
criteria.addOrder(Order.desc((String)property));
}
}
}
#Override
public void setSort(Object property, String order) {
this.property = property;
this.order = order;
}
}
SortableDataProvider
public class PersonSortableDataProvider extends SortableDataProvider {
private transient PersonDaoIface personDao;
public PersonSortableDataProvider(PersonDaoIface personDao) {
this.personDao = personDao;
}
public PersonSortableDataProvider() {
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Iterator<Person> iterator(long first, long count) {
System.out.println(getSort());
return personDao.getAll(first, count).iterator();
}
#Override
public long size() {
long result = personDao.getAllCount();
return result;
}
#Override
public IModel<Person> model(final Object object) {
return new AbstractReadOnlyModel<Person>() {
#Override
public Person getObject() {
return (Person) object;
}
};
}
}
A panel with a data table using the sortable data provider
public DataDisplayPanel(String id) {
super(id);
List<IColumn> columns = new ArrayList<IColumn>();
columns.add(new PropertyColumn(new Model<String>("First Name"), "firstName"));
columns.add(new PropertyColumn(new Model<String>("Last Name"), "lastName"));
AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable("personData", columns,
personSortableDataProvider, 8);
table.addTopToolbar(new HeadersToolbar(table, personSortableDataProvider));
add(table);
}
I have paging done no problem but I am having trouble understanding how to get sorting working with hibernate, I can see how you could do the sorting from the java side of things but given that I could potentially get large data sets back I don't like this idea.
Given my code above does anyone have a way of getting the data table, on click of either first name or last name to then make the same query found in the iterator with the additional order by clause.
You are almost there. You just need an:
addOrder(Order.asc(columnName))
The doc is here.
To anyone that encounters this situation I have the following setup:
hibernate 4, spring 4 and wicket 6
I inject using Spring and it seems wicket and spring get confused if you inject within the SortableDataProvider.
I don't know what exactly happens; when i step over the project I will have a better idea but it appears setSort is not getting set correctly, when i move the Dao class out of sortable data provider and into the page and inject it there, then pass the dao instance into sortable data provider the sorting works correctly.

Error in retrieving data which contains null from Cassandra Database using Spark/Cassandra connector

I want to retrieve data from Cassandra using Cassandra/spark Connector in java. Some of values in table are null. I use
JavaRDD<String> rdd = javaFunctions(sc).cassandraTable("test", "Sportman", Sportman.class)
.map(new org.apache.spark.api.java.function.Function<Sportman, String>() {
#Override
public String call(Sportman person) throws Exception {
return person.toString();
}
});
I got this error when trying to run the program.
TypeConversionException: Failed to convert column accomplished of table test.Sportman to java.lang.Boolean: null
The I define Sportman class like this:
public static class Sportman implements Serializable{
private UUID rowid;
private Boolean accomplished;
public Sportman(){}
public UUID getRowid() {
return rowid;
}
public void setRowid(UUID rowid) {
this.rowid = rowid;
}
public Boolean getAccomplished() {
return accomplished;
}
public void setAccomplished(Boolean accomplished) {
this.accomplished = accomplished;
}
I don't know how to change get method to fix this error. any help would be appreciated.

Categories

Resources