In Spring, CrudRepository findAll() operation working good for fetching data from the database but with the same configuration in case of saving, update & delete it's not working.
EmployeeService.java
#Service
public class EmployeeService {
#Autowired
private EmployeeRepo employeeRepoI;
#Transactional
public List<Employee> getAllEmployee() {
return (List<Employee>) employeeRepoI.findAll();
}
#Transactional
public Employee getEmployee(int id) {
return (Employee) employeeRepoI.findOne(id);
}
#Transactional
public Employee addEmployee(Employee employee) {
return (Employee) employeeRepoI.save(employee);
}
#Transactional
public Employee updateEmployee(Employee employee) {
return (Employee) employeeRepoI.save(employee);
}
#Transactional
public void deleteEmployee(int id) {
employeeRepoI.delete(id);
}
}
EmployeeRapo.java
#Repository
public interface EmployeeRepo<T, ID extends Serializable> extends CrudRepository<Employee, Long> {
List<Employee> findAll();
}
As pointed out by #Sergey Your EmployeeRepo has a wrong definition there
Try this
#Repository
public interface EmployeeRepo extends CrudRepository<Employee, Long> {
List<Employee> findAll();
}
Also your deleteEmployee() method takes an int while it should take Long as a parameter.
#Transactional
public void deleteEmployee(Long id) {
employeeRepoI.delete(id);
}
You have CrudRepository with Long type and deleteEmployee with primitive int. This values should match.
Related
I need to have generic service and repository classes in my project. I wrote it this way, but I don't know if it is correct or not.
BaseModel:
#MappedSuperclass
#Data
public class AbstractBaseEntity implements Serializable {
#Id
#GeneratedValue
private Long id;
#Version
private int version;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
public AbstractBaseEntity() {
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
}
GenericService:
public interface AbstractBaseService<T extends AbstractBaseEntity, ID extends Serializable>{
public abstract T save(T entity);
public abstract List<T> findAll(); // you might want a generic Collection if u prefer
public abstract Optional<T> findById(ID entityId);
public abstract T update(T entity);
public abstract T updateById(T entity, ID entityId);
public abstract void delete(T entity);
public abstract void deleteById(ID entityId);
// other methods u might need to be generic
}
Here I inherited from base service class and Autowired repository base classes.
#Service
#Transactional
public abstract class AbstractBaseServiceImpl<T extends AbstractBaseEntity, ID extends Serializable>
implements AbstractBaseService<T, ID> {
#Autowired
private AbstractBaseRepository<T, ID> abstractBaseRepository;
protected abstract Class<T> getDomaimClass();
protected Class<T> domainClass = this.getDomaimClass();
#Override
public T save(T entity) {
return (T) abstractBaseRepository.save(entity);
}
#Override
public List<T> findAll() {
return abstractBaseRepository.findAll();
}
#Override
public Optional<T> findById(ID entityId) {
return abstractBaseRepository.findById(entityId);
}
#Override
public T update(T entity) {
return (T) abstractBaseRepository.save(entity);
}
#Override
public T updateById(T entity, ID entityId) {
Optional<T> optional = abstractBaseRepository.findById(entityId);
if (optional.isPresent()) {
return (T) abstractBaseRepository.save(entity);
} else {
return null;
}
}
#Override
public void delete(T entity) {
abstractBaseRepository.delete(entity);
}
#Override
public void deleteById(ID entityId) {
abstractBaseRepository.deleteById(entityId);
}
GenericRepository:
I created a basic repository class and because I needed a custom Query that was not supported by jpa, I had to add two more classes.
#Repository
public interface AbstractBaseRepository<T extends AbstractBaseEntity, ID extends Serializable> extends JpaRepository<T, ID>,AbstractBaseRepositoryCustom {
}
public interface AbstractBaseRepositoryCustom<T extends AbstractBaseEntity,ID extends Serializable> {
List<T> findAllByFiter(String textQuery);
}
public class AbstractBaseRepositoryCustomImpl<T extends AbstractBaseEntity,ID extends Serializable> implements AbstractBaseRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#Override
public List findAllByFiter(String textQuery) {
Query query=entityManager.createQuery(textQuery);
return query.getResultList();
}
}
I don't know that the methods and wiring in my service class are correct. Is the repository installed correctly? Please help.
i am using spring boot JPA here is my update query looks like
#Query("update employee set sal= sal- 1000 where salary > :sal")
void updateSalary(#Param("sal") Long sal)
In service method
List<Employee> updateSalary(Long sal){
repo.updateSalary(10000l);
return repo.findAll();
}
Somehow JPA not able to understand - character.
Your Query should be
#Query("update Employee e set e.salary = e.salary-1000 where e.salary > :arg")
Also you have to mark Repository method with #Transactional and #Modifying and the return type should always be void.
Full code:
#SpringBootApplication
public class SpringBootMysqlApplication implements CommandLineRunner {
#Autowired
EmployeeRepository employeeRepository;
public static void main(String[] args) {
SpringApplication.run(SpringBootMysqlApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
if (employeeRepository.count() == 0) {
List<Employee> employees = List.of(
new Employee(null, "Josh", 1800L),
new Employee(null, "John", 800L),
new Employee(null, "Nina", 1500L),
new Employee(null, "Nate", 400L)
);
employeeRepository.saveAll(employees);
}
}
#RestController
#RequestMapping("/hello")
public static class HelloController {
#Autowired
EmployeeRepository employeeRepository;
#GetMapping(path = "/")
public Map<String, String> update() {
employeeRepository.updateSalary(1000L);
return Map.of("status", "success");
}
#GetMapping(path = "/all")
public Map<String, Object> all() {
return Map.of("status", "success", "employees", employeeRepository.findAll());
}
}
}
Repository:
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
#Transactional
#Modifying
#Query("update Employee e set e.salary = e.salary-1000 where e.salary > :arg")
void updateSalary(#Param("arg") Long arg);
}
I have a problem with my CountryServiceImpl,when I want realize method findOne in CountryServiceImpl it tells me "Inferred type 'S' for type parameter 'S' is not within its bound; should extend 'ua.com.store.entity.Country".
I wanted to fix by myself, but I don't understand what this means.
Could you please help me with this issue.
Thank you.
#Entity
#Getter
#Setter
#NoArgsConstructor
#ToString
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String countryName;
#OneToMany(mappedBy = "country")
private Set<Brand> brands = new HashSet<Brand>();
}
public interface CountryDAO extends JpaRepository<Country, Integer> {
#Query("from Country c where c.countryName=:name")
Country findByCountryName(#Param("name") String name);
}
public interface CountryService {
void save(Country country);
void delete(Country country);
List<Country> findAll();
Country findOne(int id);
Country findByCountryName(String name);
}
#Service
public class CountryServiceImpl implements CountryService {
#Autowired
private CountryDAO dao;
#Override
public void save(Country country) {
dao.save(country);
}
#Override
public void delete(Country country) {
dao.delete(country);
}
#Override
public List<Country> findAll() {
return dao.findAll();
}
#Override
public Country findOne(int id) {
return dao.findOne(id);
}
#Override
public Country findByCountryName(String name) {
return dao.findByCountryName(name);
}
}
Spring documentation defines methods getOne as follows
<S extends T> Optional<S> findOne(Example<S> example)
In your method your input parameter is 'id' of type int but not bounded to interface Example.
To find an entity with it 'id' you can use the method
Optional<T> findById(ID id)
According to your implementation you may write it
#Override
public Country findOne(int id) {
return dao.findById(id);
}
It is possible to be relevant about spring-boot version. I meet the same issue when my spring-boot version is 2.0.1.RELEASE. But after change the spring-boot version to the 1.5.9.RELEASE, it is resolved.
A 100% working solution is following:
#Override
public Country findOne(int id) {
return dao..findById(id).orElse(null);
}
I just solved this problem in my program. I don't use the findOne method, I was just saving initial data with the save method. It turns out that I had copied my repo interface from another repo interface, and forgot to update the object in "extends JpaRepository<Object, Long>" to the new object.
You need to change
from
public T getOne(ID id) {
return repository.getOne(id);
}
To
public Optional<T> getOne(ID id) {
return repository.findById(id);
}
This Worked for me...
#Override
public Country findOne(int id) {
return dao.findById(id).orElse(null);
}
I got the same problem.
ua.com.store.entity.Country -> It's like adding an external entity
You must import the correct directory of the entity "Counrty" that you will use in your project.
e.g
import com.RomanSyhock.Entity.Country;
I want to post like this :
[{
"employeeid": "1111",
"employeename": "YOA"
},
{
"employeeid": "2222",
"employeename": "OYA"
}]
My controller like this :
#PostMapping("/api/employee/save")
public Employee createEmployee(#Valid #RequestBody List<Employee> employee) {
return employeeService.save(employee);
}
Model :
#Entity
#Table(name="EMPLOYEE")
public class Employee implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
int id;
#Column(name = "EMP_ID")
int employeeid;
#Column(name = "EMPLOYEE_NAME")
String employeename;
//GETTER AND SETTER
}
When i post data, The error I get is the following:
{
"timestamp": "2018-07-13T03:36:25.898+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Invalid property 'id' of bean class [java.util.ArrayList]: Could not find field for property during fallback access!",
"path": "/api/employee/save"
}
Service :
public interface employeeService{
Employee save(List<Employee> employee);
}
Service Imp :
#Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
EmployeeRepository employeeRepository;
#Override
public Employee save(List<Employee> employee) {
return employeeRepository.save(employee);
}
}
Repository:
public interface EmployeeRepository extends Repository <Employee, Long>
Employee save(List<Employee> employee);
}
The error description is this:
Invalid property 'id' of bean class [java.util.ArrayList]: Could not find field for property during fallback access!
when using saveAll(), I Get Error message : No property saveAll found for type Employee
is there anyone who can help me ?
I have modified my question.
Regards,
Me
Problem is in this line
public Employee createEmployee(#Valid #RequestBody List<Employee> employee) {
return employeeService.save(employee); // Problem
}
employeeService.save can take only one Object of Entity in your case Employee
There are 2 ways
1.
public Boolean createEmployee(#Valid #RequestBody List<Employee> lstEmployee) {
try{
for(Employee emp : lstEmployee){
employeeService.save(employee);
}
return true;
}catch(Exception e){}
return false;
}
2.
Use saveAll instead
public Employee createEmployee(#Valid #RequestBody List<Employee> employee) {
return employeeService.saveAll(employee);
}
Edit 1:
After adding service class it looks like you are manually implementing so
Option 1:
I would suggest you directly use EmployeeRepository in your controller class.
As by manually overriding there methods you are not actually
enjoying benefit of using Repository
#Autowired
EmployeeRepository employeeRepository;
#PostMapping("/api/employee/save")
public Employee createEmployee(#Valid #RequestBody List<Employee> lstEmployee) {
return employeeRepository.saveAll(lstEmployee);
}
Option 2:
Longer way, change your implementation like this. There might be some error for Object but it should give you an idea
public interface employeeService{
Employee save(Employee employee);
public <S extends User> List<S> saveAll(Iterable<S> entites);
}
#Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
EmployeeRepository employeeRepository;
#Override
public Employee save(Employee employee) {
return employeeRepository.save(employee);
}
#Override
public List<Employee> saveAll(List<Employee> employee) {
return employeeRepository.saveAll(employee);
}
}
I assume you're using spring-data-jpa repository. Let know if it is otherwise. You're trying to use the save api which only saves one entity. What you need is saveAll() which saves all the given entity. Please read the documentation.
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#saveAll-java.lang.Iterable-
Edit: Updated answer to save all records
The save method will return all the employees so change the type to List<Employees>
public interface EmployeeRepository extends Repository <Employee, Long>
List<Employee> saveAll(List<Employee> employee);
}
Even better use one of the pre-supplied interfaces for simple CRUD operations for example CrudRepository. It reduces the boilerplate code that you may have write.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories
public interface EmployeeRepository extends CrudRepository <Employee, Long>
}
My professor gave a sample Spring MVC ORM project with Hibernate but I can not figure out the sequence of events involved, in particular about the usage of service business object.
This is just a little part of the project, just to make my ideas clearer.
domain:
#Entity
#Table(name = "department")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long uid;
private String name;
#OneToMany(mappedBy="department",cascade=CascadeType.PERSIST)
private List<Employee> employees = new ArrayList<Employee>();
public Department() {
}
public Department(String name) {
this.name = name;
}
// getters, setters, hashcode() and equals(), toString()...
controller:
#Controller
#RequestMapping("/department")
public class DepartmentController {
#Autowired
#Qualifier("departmentBO")
private DepartmentBO departmentBO;
static final Logger logger = Logger.getLogger(DepartmentController.class);
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String departmentHome(Model model) {
logger.debug("department home() invoked");
List<Department> list = departmentBO.findAllDepartments();
model.addAttribute("list", list);
return "departments";
}
// i'll paste just the first controller ;)
business:
public interface DepartmentBO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department department);
public void update(Department department);
}
business/impl:
#Service
#Transactional
public class DepartmentBoImpl implements DepartmentBO {
#Autowired
private DepartmentDAO departmentDao;
static final Logger logger = Logger.getLogger(DepartmentBoImpl.class);
#Override
public void save(Department department) {
departmentDao.save(department);
}
#Override
public void update(Department department) {
departmentDao.update(department);
}
#Override
public void delete(long uid) {
departmentDao.delete(uid);
}
#Override
public List<Department> findAllDepartments() {
return departmentDao.findAllDepartments();
}
#Override
public Department findByUid(Long uid) throws DataAccessException {
return departmentDao.findByUid(uid);
}
}
dao:
public interface DepartmentDAO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department user);
public void update(Department user);
}
dao/impl:
#Repository
public class DepartmentDAOImplSf implements DepartmentDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void delete(long uid) {
Department department = (Department) sessionFactory.getCurrentSession()
.get(Department.class, uid);
sessionFactory.getCurrentSession().delete(department);
}
#Override
public void save(Department department) {
sessionFactory.getCurrentSession().save(department);
}
#Override
public void update(Department department) {
sessionFactory.getCurrentSession().saveOrUpdate(department);
}
#Override
public List<Department> findAllDepartments() {
List<Department> list = (List<Department>) sessionFactory
.getCurrentSession()
.createQuery("FROM Department").list();
return list;
}
#Override
public Department findByUid(Long uid) {
Department department = (Department) sessionFactory
.getCurrentSession().get(Department.class, uid);
return department;
}
}
I know that the order is: domain model -> controller-> service -> dao ->db, but why use a DepartmentBO? and why DepartmentBoImpl autowired DepartmentDao? Who of them act first? Something that i'm not understanding is messing up my conception of how it works and the sequence of the process..
Thanks for your help ;)
EDIT: "
In few words my question is, what is the sequence of this code? user goes on the /home page that redirect on "departments" page. But what happen before this --> "List list = departmentBO.findAllDepartments();" ?;)
When the departmentBO.findAllDepartments() method is called if you look at the code it invokes the sessionFactory. That is an internal factory class in Hibernate that basically builds a transactional connection to the DB in order to run a query. You are defining the query in the createQuery method and then ultimately executing it with the list() method. These two methods are part of the database session that Hibernate has instantiated.
Departments Page -> departmentBO.findAllDepartments() -> sessionFactory -> createQuery -> list()
Or in pseudo code-ish
Departments Page -> execute findAllDepartments method -> fetch / build a database connection -> define the query -> execute the query -> Return the list!