Spring Hibernate - Dao Return By Id - spring

I use Spring & Hibernate and i would like to get a product with his id in my DAO.
#Repository
#Transactional
public class ProductDaoImpl implements ProductDao {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private SessionFactory sessionFactory;
public List<Product> getProductList() {
return sessionFactory.getCurrentSession().createQuery("from Product p order by p.productName asc").list();
}
public Product getProductById(int productId) {
String hql = "from Product p where p.productId = :id";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setInteger("id", productId);
return null;
}
}
For example when i would like to get all my products i return list of them (calling function getProductList() ), but now i want to call getProductById but i don't know how i could return something with the "Product" type.
Thanks.

In your getProductById(int productId) method:
return (Product) query.uniqueResult();

Related

Always getting a empty object in unitTest JPA/Hibernate

I am currently trying if my functions work with my current database but I keep getting an empty object back. My Test is the following:
#Test
public void findJobOfferByIdReturnsCorrectJobOffer() {
User user = UserBuilder.anUser().build();
JobOffer firstJobOffer = JobOfferBuilder.aJobOffer()
.withId(108L)
.withCompany(user)
.build();
JobOffer secondJoboffer = JobOfferBuilder.aJobOffer()
.withAmountPerSession(55)
.withCompany(user)
.withId(208L)
.withJobDescription("Software Tester in PHP")
.build();
userDao.saveUser(user);
jobOfferDao.saveJobOffer(firstJobOffer);
jobOfferDao.saveJobOffer(secondJoboffer);
entityManager.clear();
entityManager.flush();
Optional<JobOffer> retrievedJobOffer = jobOfferDao.findJobOfferById(firstJobOffer.getId());
assertTrue(retrievedJobOffer.isPresent());
JobOffer jobOffer = retrievedJobOffer.get();
assertEquals(jobOffer.getId(), firstJobOffer.getId());
assertNotEquals(jobOffer.getId(), secondJoboffer.getId());
}
The Test uses the following DAOImpl repository:
#Repository
public class JobOfferDaoImpl implements JobOfferDao {
#PersistenceContext
private EntityManager entityManager;
private static final Logger LOGGER = LogManager.getLogger(UserDaoImpl.class);
#Override
public Optional<JobOffer> findJobOfferById(Long id) {
TypedQuery<JobOffer> jobOfferQuery = entityManager.createNamedQuery("findJobOfferById", JobOffer.class);
jobOfferQuery.setParameter("jobOfferId", id);
try {
return Optional.of(jobOfferQuery.getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
}
#Transactional
public void saveJobOffer(JobOffer jobOffer) {
if (findJobOfferById(jobOffer.getId()).isEmpty()) {
entityManager.merge(jobOffer);
LOGGER.info(String.format("Joboffer with id %d is inserted in the database", jobOffer.getId()));
} else {
throw new JobOfferNotFoundException();
}
}
}
And the Query to select the correct jobOffer for "findJobOfferById" is the following:
#NamedQuery(name = "findJobOfferById", query = "SELECT j from JobOffer j WHERE j.id = :jobOfferId"),
When trying to debug I get the following:
In the Test you shouldn't give your own ID. Change it with:
.withId(null)
And in the DAO you have to Persist the jobOffer and actually add it. With merge you are modifying it.
entityManager.persist(jobOffer);

Mockito Test for Spring NamedJDBC Template

I am trying to figure out mickito test for Named Jdbc Template but unable to do so. I did googling but did not find any accurate result. Below is example Code.
Student.class
#Data
public class Student {
private int id;
private String name;
private String address;
public Student(ResultSet rs) throws SQLException {
id = rs.getInt("id");
name = rs.getString("name");
address = rs.getString("address");
}
}
Student class takes ResultSet argument in constructor and mapped all column to variable .
StudentService.class
public class StudentService {
#Autowired
#Qualifier("namedJdbcTemplate")
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public Student gerStudent(String id) {
Student student;
String selectStudent = "select id , name ,address from student where id=:id";
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();
mapSqlParameterSource.addValue(id, "id");
student = namedParameterJdbcTemplate.query(selectStudent, mapSqlParameterSource, resultSet -> {
Student response = new Student(resultSet);
return response;
});
return student;
}
}
Can anyone please help on Mockito Test for below line of code?
student = namedParameterJdbcTemplate.query(selectStudent, mapSqlParameterSource, resultSet -> {
Student response = new Student(resultSet);
return response;
});

DeleteById method returns null

I have tried to delete a row from database using Spring data deleteById method but it returns null.
ProductServiceImpl
public void removeOne(Long id) {
Product product = findById(id);
productRepository.deleteById(product);
ProductRepository
public interface ProductRepository extends CrudRepository<Product, Long> {
void deleteById(Product product);
Controller
#RequestMapping(value="/remove", method=RequestMethod.POST)
public String remove(#ModelAttribute("id") String id, Model model) {
productService.removeOne(Long.parseLong(id.substring(10)));
List<Product> productList = productService.findAll();
model.addAttribute("productList", productList);
System.out.println("deleted successfully !!!!");
return "redirect:/product/productList";
}
Why you write it complex. Some code not necessary .First, you extends CrudRepository,it mean you don't need create custom method void deleteById(Product product); because crud contain method deleteById.
Second, Controller why you using : #RequestMapping(value="/remove", method=RequestMethod.POST) . I think it must : #DeleteMapping("/remove") . And in controller only call.
#Autowired
private ProductRepository productRepository;
#DeleteMapping("/remove/{id}")
public String remove(#PathVariable String id) {
productRepository.deleteById(id);
return "redirect:/product/productList";
}
#Autowired
private ProductRepository productRepository;
#RequestMapping(value="/remove", method=RequestMethod.POST)
public String remove(#RequestParam String id) {
productRepository.deleteById(id);
return "redirect:/product/productList";
}

How to write a search class to accept any type of parameter?

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.

Determine if parent has one or more children using hibernate

I have two models, Purchase and Tag.
A Purchase can have many Tags (One to Many relationship).
What is the best (Efficent/Cleanest/etc) way to return all purchases that have one or more tags? (The actual tag entities dont have to be returned).
I'm currently using a column in the purchase table to determine if it has been tagged but would like to remove it (See PurchaseDAO for it been used)
PurchaseController:
#RequestMapping(value = "purchases/tagged", method = RequestMethod.GET)
#ResponseBody
public final List<Purchase> getTagged()
{
return RestPreconditions.checkNotNull(purchaseService.getTagged());
}
#RequestMapping(value = "purchases/pending", method = RequestMethod.GET)
#ResponseBody
public final List<Purchase> getPending()
{
return RestPreconditions.checkNotNull(purchaseService.getPending());
}
PurchaseService:
#Service
public class PurchaseService implements IPurchaseService
{
#Autowired
private IPurchaseDAO purchaseDAO;
public PurchaseService()
{
}
#Transactional
public List<Purchase> getAll()
{
return purchaseDAO.findAll();
}
#Transactional
public List<Purchase> getPending()
{
return purchaseDAO.getPending();
}
#Transactional
public List<Purchase> getTagged()
{
return purchaseDAO.getTagged();
}
}
PurchaseDAO:
#Repository
public class PurchaseDAO extends AbstractJpaDAO<Purchase> implements IPurchaseDAO {
#PersistenceContext
EntityManager entityManager;
public PurchaseDAO() {
setClazz(Purchase.class);
}
public List<Purchase> getPending() {
return entityManager.createQuery("from Purchase where tagged = 0")
.getResultList();
}
public List<Purchase> getTagged() {
return entityManager.createQuery("from Purchase where tagged = 1")
.getResultList();
}
}
Both my Purchase and Tag DAOs extend the following AbstractJpaDAO:
public abstract class AbstractJpaDAO<T extends Serializable> implements
IAbstractJpaDAO<T> {
private Class<T> clazz;
#PersistenceContext
EntityManager entityManager;
public void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T findOne(final Long id) {
return entityManager.find(clazz, id);
}
public List<T> findAll() {
return entityManager.createQuery("from " + clazz.getName())
.getResultList();
}
public void save(final T entity) {
entityManager.persist(entity);
}
}
Thanks
JB Suggestion Update
After changing PurchaseDAO getTagged() to:
public List<Purchase> getTagged() {
return entityManager.createQuery("SELECT p FROM Puchase p INNER JOIN p.tags")
.getResultList();
}
I get following error:
TRACE [http-bio-8080-exec-3] o.s.w.c.s.AnnotationConfigWebApplicationContext [AbstractApplicationContext.java:322] Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/PurchaseAPIServer/api/purchases/tagged]; client=[192.168.1.17]; method=[GET]; servlet=[PurchaseAPIServer]; session=[null]; user=[null]; time=[411ms]; status=[failed: org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.ast.QuerySyntaxException: Puchase is not mapped [SELECT p FROM Puchase p JOIN p.tags tag]; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.ast.QuerySyntaxException: Puchase is not mapped [SELECT p FROM Puchase p JOIN p.tags tag]]
select p from Purchase p inner join p.tags
The inner join just makes there is at least one tag for the purchase.

Resources