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);
}
Related
I am testing a DAO class using JUnit and I am getting a nullpointerexception which I am not sure why as I am initiating the service class. The following is the test class:
public class RegisterTest {
private UserDaoImpl userservice = new UserDaoImpl();
#Mock
JdbcTemplate jdbcTemplate;
User user;
#Before
public void setUp() {
user = new User();
}
#Test
public void testSetAddress() {
user.setAddress("A");
assertEquals(user.getAddress(), "A");
}
#Test
public void testSetEmail() {
user.setEmail("B");
assertEquals(user.getEmail(), "B");
}
#Test
public void testSetFirstname() {
user.setFirstname("C");
assertEquals(user.getFirstname(), "C");
}
#Test
public void testSetLastname() {
user.setLastname("D");
assertEquals(user.getLastname(), "D");
}
#Test
public void testSetPassword() {
user.setPassword("E");
assertEquals(user.getPassword(), "E");
}
#Test
public void testSetUsername() {
user.setUsername("F");
assertEquals(user.getUsername(), "F");
}
#Test
public void testRegister() {
userservice.register(user);
String username = user.getUsername();
assertEquals(userservice.findByUsername(username), 1);
}
}
The following is the UserDaoImpl
public class UserDaoImpl implements UserDao {
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
DataSource datasource;
#Autowired
JdbcTemplate jdbcTemplate;
public List<User> findByUsername(String username) {
String sql = "select * from users where username='" + username +
"'";
List<User> users = jdbcTemplate.query(sql, new UserMapper());
return users;
}
public int register(User user) {
// If username is unique
String uniqueusername = "select * from users where username='" +
user.getUsername() + "'";
List<User> users = jdbcTemplate.query(uniqueusername, new
UserMapper());
if(users.size() == 0) {
// encode password
String encryptedPassword =
passwordEncoder.encode(user.getPassword());
// Updating database with new user
String sql = "insert into users values(?,?,?,?,?,?)";
return jdbcTemplate.update(sql, new Object[] {
user.getUsername(),
encryptedPassword,
user.getFirstname(),
user.getLastname(),
user.getEmail(),
user.getAddress() });
}
else {
return 0;
}
}
How can I inject the class in the test class? I guess the reason why the nullpointerxeception is because the dao class is not being injected properly in the test class
You should run your test with adequate runner
RunWith(MockitoJunitRunner.class)
public class RegisterTest {
Then you need to inject your mock inside the DAO
#InjectMocks
private UserDaoImpl userservice = new UserDaoImpl();
I'm using Spring Boot, Spring Data REST, Spring HATEOAS. I created a #RepositoryRestController:
#Api(tags = "Ticket Entity")
#RepositoryRestController
#PreAuthorize("isAuthenticated()")
public class TicketController extends RevisionController<TransitCertificate> {
private Logger log = LogManager.getLogger();
#Autowired
private LocalValidatorFactoryBean validator;
#Autowired
private TicketService ticketService;
#Autowired
private EnumTranslator enumTranslator;
#SuppressWarnings("rawtypes")
#Autowired
private PagedResourcesAssembler pagedResourcesAssembler;
#Autowired
private MessageSource messageSource;
#Autowired
private Javers javers;
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(validator);
}
#PostMapping(path = "/tickets")
public ResponseEntity<?> save(#RequestBody(required = true) #Valid Ticket ticket, PersistentEntityResourceAssembler resourceAssembler) {
return new ResponseEntity<>(resourceAssembler.toResource(ticketService.save(ticket)), HttpStatus.OK);
}
}
I need to intercept the event before the Ticket object is persisted. I created my handler:
#Component
#RepositoryEventHandler(Ticket.class)
public class TicketHandler {
private Logger log = LogManager.getLogger();
#Autowired
private WorkShiftRepository workShiftRepository;
#HandleBeforeCreate
public void handleBeforeCreates(Ticket ticket) {
WorkShift workShift = workShiftRepository.findByAgentUsernameAndEndDateIsNull();
if (workShift != null) {
ticket.setWorkShift(workShift);
}
}
}
and this is my TicketRepository:
#Transactional
#PreAuthorize("isAuthenticated()")
public interface TicketRepository extends PagingAndSortingRepository<Ticket, Long> {
#RestResource(exported = false)
#Override
public <S extends Ticket> Iterable<S> save(Iterable<S> entities);
#RestResource(exported = false)
#Override
public <S extends Ticket> S save(S entity);
#RestResource(exported = false)
#Override
public void delete(Long id);
#RestResource(exported = false)
#Override
public void delete(Ticket entity);
#Query(value = "SELECT MAX(number) FROM Ticket t WHERE t.block=:ticketBlock")
public Long findMaxNumber(#Param("ticketBlock") TicketBlock ticketBlock);
}
as described in the documentation but the event is not emitted. Like described here I'm using the #HandleBeforeCreate annotation. Am I doing something wrong?
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.
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!
This question already has answers here:
org.hibernate.LazyInitializationException: How to properly use Hibernate's lazy loading feature
(3 answers)
Closed 6 years ago.
I am trying to get the orders by using the getOrders(String domain) function from domain DAO
this is the code:
Set<Order> orders;
orders = domainService.getOrders('google.com');
but I keep getting this error
failed to lazily initialize a collection of role: com.latinon.reportator.model.Domain.ordersDomain, could not initialize proxy - no Session
which one is the correct way to set the lazy type without getting the error
pojos
domain
#Entity
#Table(name="Domain")
public class Domain {
private Set<Order> ordersDomain = new HashSet<Order>(0);
private Set<User> userDomain = new HashSet<User>(0);
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name="Order_Domain", joinColumns={
#JoinColumn(name="Order_Domain_Domain_id")
},inverseJoinColumns={
#JoinColumn(name="Order_Domain_Order_id", nullable=false,updatable=false)
})
public Set<Order> getOrdersDomain() {
return ordersDomain;
}
public void setOrdersDomain(Set<Order> ordersDomain) {
this.ordersDomain = ordersDomain;
}
}
order
#Entity
#Table(name="Order")
public class Order {
private Set<Domain> orderDomains = new HashSet<Domain>(0);
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name="Order_Domain", joinColumns={
#JoinColumn(name="Order_Domain_Order_id",nullable=false,updatable=false)
}, inverseJoinColumns={
#JoinColumn(name="Order_Domain_Domain_id",nullable=false,updatable=false)
})
public Set<Domain> getOrderDomains() {
return orderDomains;
}
public Set<Domain> getOrderDomains() {
return orderDomains;
}
}
DAOs
Domain
public interface DomainDAO {
public void saveDomain(Domain domain);
public void updateDomain(Domain domain);
public Domain getDomainById(Integer id);
public Domain getDomain(String domain);
public void deleteDomain(Integer id);
public Set<Order> getOrders(String domain);
}
Order
public interface OrderDAO {
public void saveOrder(Order order);
public void updateOrder(Order order);
public Order getOrderById(Integer id);
public void deleteOrder(Integer id);
public Order getOrderByAdUnit(String adUnitId);
}
servicios
domain
public interface DomainService {
public void saveDomain(Domain domain);
public void updateDomain(Domain domain);
public Domain getDomainById(Integer id);
public void deleteDomain(Integer id);
public Domain getDomain(String domain);
public Set<Order> getOrders(String domain);
}
domain service implementation
#Service
public class DomainServiceImpl implements DomainService {
private DomainDAO domainDao;
public DomainDAO getDomainDao() {
return domainDao;
}
public void setDomainDao(DomainDAO domainDao) {
this.domainDao = domainDao;
}
public DomainServiceImpl() {
// TODO Auto-generated constructor stub
}
#Transactional
public Set<Order> getOrders(String domain) {
Domain domainAux = this.domainDao.getDomain(domain);
return domainAux.getOrdersDomain();
}
}
order
public interface OrderService {
public void saveOrder(Order order);
public void updateOrder(Order order);
public Order getOrderById(Integer id);
public void deleteOrder(Integer id);
public Order getOrderByAdUnit(String adUnitId);
}
order service implementation
#Service
public class OrderServiceImpl implements OrderService {
private OrderDAO orderDAO;
public OrderDAO getOrderDAO() {
return orderDAO;
}
public void setOrderDAO(OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}
public OrderServiceImpl() {
// TODO Auto-generated constructor stub
}
#Transactional
public Order getOrderByAdUnit(String adUnitId) {
return this.orderDAO.getOrderByAdUnit(adUnitId);
}
}
In Hibernate if something is lazily loaded, it should be loaded while a session is available. After session is closed, it can't be loaded (lazy init exception)
Inside DomainServiceImpl.getDomain method say something like:
Hibernate.initialize(domainAux.getOrdersDomain())
If your DAO's are your session boundaries, do above in respective DAO methods.