I am trying to write a query using SpringData Jpa using the #Query annotation on the interface method declaration.
The interface looks like this:
public interface MyService {
#Query("select * from employee e where e.projectId = ?1")
public List<Employee> getEmployeesWorkingOnAProject(String projectId) throws MyException;
}
I also have a class that implements this interface:
#Component
public class ProjectServiceImpl implements ProjectService {
}
I am not sure how will this query execution work and how to provide an implementation for getEmployeesWorkingOnAProject method in the imeplementing class.
Thanks
In your Interface, you should extend JpaRepository (or any other spring data repository).
Then you can just autowire your interface in any spring bean class and call getEmployeesWorkingOnAProject().
So for example:
public interface MyService extends JpaRepository<Employee,Long> {
#Query("select * from employee e where e.projectId = ?1")
public List<Employee> getEmployeesWorkingOnAProject(String projectId) throws MyException;
}
#Component
public class ProjectServiceImpl implements ProjectService {
private final MyService service;
#Autowire // not necessary in spring 4.3 +
public ProjectServiceImpl(MyService service) {
this.service = service;
}
public List<Employee> getEmployeesWorkingOnAProject(String projectId) throws MyException {
return service.getEmployeesWorkingOnAProject();
}
}
However, Spring Data is able to build a query for you, so is no reason for writing your own query in this example.
Spring Data way:
public interface MyService extends JpaRepository<Employee,Long> {
public List<Employee> findAllByProjectId(String projectId) throws MyException;
}
First things first. Your interface have to extend some kind of Spring Data Repository, for example JpaRepository.
Second thing, in the Query annotation, you can put two types of query. JPQL or native SQL query. This can be controlled by a flag on the query annotation (nativeQuery).
In JPQL, your query should look like the following:
#Query("select e from employee e where e.projectId = ?1")
Related
How to add a user define annotation in spring jpa save method only.
I have created a annotation and wanted to use it on the save method of the repository, but the save method is inherited method from CrudRepository of JPA, not sure how can annotation be applied on only that method and not the other method of that repository.
Tried overriding that method in the repository interface and applied the annotation but it didn't worked
Please refer the code below -
Annotation :
#Target({ ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}
#Aspect
#Configuration
#Slf4j
#ComponentScan(value = "com.somepackage.service")
public class MyAnnotationInterceptor {
#Value("${val}")
private String val;
#Around("#annotation(com.somepackage.service.application.annotation.MyAnnotation)")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
if("TEST".equalsIgnoreCase(val)){
log.info("Test Event")
}else{
joinPoint.proceed();
}
}
}
Repository :
#Transactional
public interface EmployeeEntityRepository extends CrudRepository<EmployeeEntity, String> {
List<EmployeeEntity> findAllByEmpIdAndStatusNot(String empId, String status);
#Query("SELECT emp.empId FROM EmployeeEntity emp WHERE emp.orderId IN ?1")
List<String> findEmployeeIds(List<String> orderIds);
#Override
#MyAnnotation
<S extends EmployeeEntity> Iterable<S> save(Iterable<S> iterable);
}
Service Class:
class EmployeeService {
#Autowired
EmployeeEntityRepository employeeEntityRepo;
public void saveEmployee(List<EmployeeEntity> employeeData) {
employeeEntityRepo.save(employeeData);
employeeEntityRepo.clearCache(employeeData);
/***
.
.
.
Some other logic calculations
.
.
***/
}
}
I'm using Spring to communicate with mysql db.
I've got an Entity class and an interface that extends CrudRepository.
Everything works great - read/write etc.
I want to 'extend' the findAll methods. I want to manipulate the received data from findAll before returning it.
user class:
#Entity
#Table(name = "user")
public class User
{
private String name;
private String age;
private String type;
getters/setters
}
repo:
#Repository
public interface UserRepo extends CrudRepository<User, Long> {
List<User> findAll();
Map<String, String> afterManipulatedFindAllData();
}
I want that afterManipulatedFindAllData() will manipulate findAll data as I like.
Is that possible?
added
after reviewing #BoristheSpider link:
interface UserRepository {
Map<String, String> afterManipulatedFindAllData();
}
class UserRepositoryImpl implements UserRepository{
public Map<String, String> afterManipulatedFindAllData() {
////how this method receive the 'findAll' data?//////
}
}
public interface UserRepo extends CrudRepository<User, Long>, UserRepository
{
List<User> findAll();
Map<String, String> afterManipulatedFindAllData();
}
Thanks a lot,
Avi
You can always define new methods in the repository by specifying a JPA query for them:
#Component
public interface UsersRepository extends JpaRepository<User, UUID> {
public List<User> findByEntityStatus(EntityStatus status);
#Query("from User user left outer join fetch user.areas where user.code = :code")
public User findByCode(#Param("code") String code);
}
Maybe this could work for you?
I'm trying to follow code reusing best practices.
I have generic DAO interface with some common methods:
public interface DaoInterface<T> {
T findById(int id);
//...more methods...
}
and its implementation class:
public class GenericDao<T> implements DaoInterface<T> {
#SuppressWarnings("unchecked")
private final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
#Autowired
protected SessionFactory sessionFactory;
#Override
#SuppressWarnings("unchecked")
public T findById(int id) {
Session session = sessionFactory.getCurrentSession();
return (T) session.get(persistentClass, id);
}
//...more methods...
}
Then my every concrete implementation class extends GenericDao and implements its interface.
I also have Service layer in my application. Some Services' methods completely delegate their work to DAO classes. So in the each concrete Service implementation I autowire appropriate DAO class and call its methods.
So now it looks:
public interface CustomerService {
Customer findById(int id);
}
and implementation:
#Service
#Transactional(readOnly = true, rollbackFor = Exception.class)
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao customerDao;
#Override
public Customer findById(int id) {
return customerDao.findById(id);
}
}
My question is - how to generify Service classes in the same way as DAO? So that my concrete class will look:
public class CustomerServiceImpl extends GenericService<Customer> implements CustomerService {
.....
}
The problem is that I cannot autowire DAO class in Generic Service:
#Autowired
private GenericDao<T> dao;
so that I could call dao's methods.
Should I do it in the constructor?
And one more question - where is the right place to annotate methods with #Transactional - in generic class or in every implementation class?
You have to create an instance of a generic Dao and put in the service layer some decision:
#Repository
public class GenericDao implements DaoInterface<T> {
//The type must be aquired at runtime,otherwise it may not be thread safe
#Autowired
protected SessionFactory sessionFactory;
#Override
#SuppressWarnings("unchecked")
public T findById(int id,Class<?> persistenceClass) {
Session session = sessionFactory.getCurrentSession();
return (T) session.get(persistenceClass, id);
}
//...more methods...
}
Also if you need a good generic repository layer take a look for Spring Data Jpa
This will make one and only one instance of the GenericDao.
Next you have 2 choice:
Create a singleton services for all your needs
Create a class service for every entity
abstract class GenericService<T> {
#Autowired
protected GenericDao dao;
#SuppressWarnings("unchecked")
protected final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
#Override
public T findById(int id) {
return dao.findById(id,persistenceClass);
}
}
Now every one of your service must extends the GenericService with a supplied persistence type and the job is done.
I've three JPA entity classes A, B and C with the following hierarchy:
A
|
+---+---+
| |
C B
That is:
#Entity
#Inheritance
public abstract class A { /* ... */ }
#Entity
public class B extends A { /* ... */ }
#Entity
public class C extends A { /* ... */ }
Using Spring Data JPA, what is the best way to write repositories classes for such entities?
I know that I can write these:
public interface ARespository extends CrudRepository<A, Long> { }
public interface BRespository extends CrudRepository<B, Long> { }
public interface CRespository extends CrudRepository<C, Long> { }
but if in the class A there is a field name and I add this method in the ARepository:
public A findByName(String name);
I've to write such method also in the other two repositories, and this is a bit annoying.. Is there a better way to handle such situation?
Another point I would like to have is that ARespository should be a read-only repository (i.e. extend the Repository class) while the other two repositories should expose all the CRUD operations.
Let me know possible solutions.
I used the solution also described in this post from Netgloo's blog.
The idea is to create a generic repository class like the following:
#NoRepositoryBean
public interface ABaseRepository<T extends A>
extends CrudRepository<T, Long> {
// All methods in this repository will be available in the ARepository,
// in the BRepository and in the CRepository.
// ...
}
then I can write the three repositories in this way:
#Transactional
public interface ARepository extends ABaseRepository<A> { /* ... */ }
#Transactional
public interface BRepository extends ABaseRepository<B> { /* ... */ }
#Transactional
public interface CRepository extends ABaseRepository<C> { /* ... */ }
Moreover, to obtain a read-only repository for ARepository I can define the ABaseRepository as read-only:
#NoRepositoryBean
public interface ABaseRepository<T>
extends Repository<T, Long> {
T findOne(Long id);
Iterable<T> findAll();
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
and from BRepository extend also the Spring Data JPA's CrudRepository to achieve a read/write repository:
#Transactional
public interface BRepository
extends ABaseRepository<B>, CrudRepository<B, Long>
{ /* ... */ }
I'm building a small application using Spring and Spring Data JPA and I need to use the CrudRepository methods in the service layer, so I made 2 classes: GenericService and GenericServiceImpl. But I don't know if this is the right or even the best approach.
Here is an example:
POJO:
#Entity
public class User {
#Id
private Long id;
private String username;
}
DAO:
public interface UserDAO extends CrudRepository<User, Long> {
User findOneByUsername(String username);
}
Generic service
public interface GenericService<T, ID extends Serializable> {
<S extends T> S save(S entity);
}
Service
public interface UserService extends GenericService<User, Long> {
User findOneByUsername(String username);
}
Generic service impl.
public class GenericServiceImpl<T, ID extends Serializable> implements GenericService<T, ID> {
#Autowired
private CrudRepository<T, ID> repository;
#Override
public <S extends T> S save(S entity) {
return repository.save(entity);
}
}
Service Impl.
#Service
#Transactional
public class UserServiceImpl extends GenericServiceImpl<User, Long> implements UserService {
#Autowired
private UserDAO userDAO;
#Override
public User findOneByUsername(String username) {
userDAO.findOneByUsername(username);
}
}
Yes, you're providing your own impl that's may do custom things while still reusing the Derived queries from Spring JPA's CrudRepository. I've seen that a lot. :) We need to do that if we want to do our own computation before calling the Derived methods. After all, that computation may very well be part of a repository, so it doesn't make sense to put that logic in the service. But in your scenario, if there are no such custom computations, then this indirection isn't needed. As a commenter mentioned, you should directly use the UserDao interface. :)