How to access entity manager with spring boot and spring data - spring-boot

How can I get access to the Entity Manager in the repository when using Spring Boot and Spring Data?
Otherwise, I will need to put my big query in an annotation. I would prefer to have something more clear than a long text.

You would define a CustomRepository to handle such scenarios. Consider you have CustomerRepository which extends the default spring data JPA interface JPARepository<Customer,Long>
Create a new interface CustomCustomerRepository with a custom method signature.
public interface CustomCustomerRepository {
public void customMethod();
}
Extend CustomerRepository interface using CustomCustomerRepository
public interface CustomerRepository extends JpaRepository<Customer, Long>, CustomCustomerRepository{
}
Create an implementation class named CustomerRepositoryImpl which implements CustomerRepository. Here you can inject the EntityManager using the #PersistentContext. Naming conventions matter here.
public class CustomCustomerRepositoryImpl implements CustomCustomerRepository {
#PersistenceContext
private EntityManager em;
#Override
public void customMethod() {
}
}

In case you have many repositories to deal with, and your need in EntityManager is not specific for any particular repository, it is possible to implement various EntityManager functionality in a single helper class, maybe something like that:
#Service
public class RepositoryHelper {
#PersistenceContext
private EntityManager em;
#Transactional
public <E, R> R refreshAndUse(
E entity,
Function<E, R> usageFunction) {
em.refresh(entity);
return usageFunction.apply(entity);
}
}
The refreshAndUse method here is a sample method to consume a detached entity instance, perform a refresh for it and return a result of a custom function to be applied to the refreshed entity in a declarative transaction context. And you can add other methods too, including query ones...

Related

#Transactional has no effect on JpaRepository

I have a parent transaction at controller layer, but I want to start a new transaction when I call a repository, to achieve this I tried annotating Repository interface as below
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface EventRepo extends JpaRepository<Event, Integer>{ }
However this seems to not start a new transaction upon calls to EventRepo#save. Why?
Here is my service layer.
public interface IApplicationService {
void save(Event event);
}
#Service
public class ApplicationService implements IApplicationService {
#Autowired
private EventRepo eventRepo;
#Override
public void save(Event event) {
eventRepo.save(event);
}
}
It is in turn called from controller layer
#RequestMapping(value="/{indicator}", method=RequestMethod.POST)
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
#ResponseBody
public String processRequest(#PathVariable Integer indicator) {
Event event = new Event("Student1");
service.save(event);
if(indicator != 0) {
throw new RuntimeException();
}
return "Success";
}
However everything works perfectly if I annotate Service interface with #Transactional
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface IApplicationService {
void save(Event event);
}
When I say working what is mean is, if I run the below curl commands I will see 2 rows in h2 db for Event entity
curl -X POST http://localhost:8080/1
curl -X POST http://localhost:8080/0
I understand it is good to control transactions at Service layer then repository or controller layer, constructing situation this way makes it easy to demonstrate the problem.
Spring boot starter version is 2.5.6
below dependencie have versions managed by springboot starter
spring-boot-starter-data-jpa
spring-boot-starter-web
lombok
h2
Here is a thread that suggests it should be ok to annotate Repository layer although discourages it.
#Transactional on a JpaRepository
In this Spring article we can read the following:
Additionally, we can get rid of the #Transactional annotation for the method as the CRUD methods of the Spring Data JPA repository implementation are already annotated with #Transactional.
To me, this means that whatever #Transactional annotation you add to your EventRepo will be overridden by the #Transactional annotation mentioned above in the CRUD methods. Having said that, I really doubt #Transactional annotation has any effect in JpaRepository methods. It would have in your own custom methods, but it seems to me that it has none in the inherited methods.
In order to apply your own transactional settings in EventRepo#save override the save method:
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface EventRepo extends JpaRepository<Event, Integer>{
#Override
Event save(Event event);
}
Explanation
Spring ignores your #Transactional annotation because it cannot find the save method in the EventRepo proxy and applies the default transaction settings from the parent CrudRepository interface.
Further reading: How Does Spring #Transactional Really Work?

How to access Entity Manager within a service in spring boot project?

I've googled so many times for how to access entity manager in spring boot, and did what posts said, but it didn't work. I want to access Entity Manager so that i can do some custom query operation. Here i defined the custom interface in a dependent package named 'customrepository':
public interface PostRepositoryCustom {
void refresh(Post post);
}
Then I implemented this interface in another package named 'customrepositoryimpl':
public class CustomPostRepositoryImpl implements PostRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Override
public void refresh(Post post) {
em.refresh(post);
}
}
Finally, I defined a standard repository interface which extends 'CrudRepository' and the custom repository:
public interface PostRepository extends CrudRepository<Post,Long>,PostRepositoryCustom {}
Every steps i followed What i googled and Official Documents, BUT when i run my application, i get this:
Error creating bean with name 'postRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract void com.example.demo.customrepository.PostRepositoryCustom.refresh(com.example.demo.model.Post)! No property refresh found for type Post!
Why? Anyone tell me where should i correct my mistakes?
Spring cannot locate the beans, so try annotate with #Repository
#Repository
public class CustomPostRepositoryImpl implements PostRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Override
public void refresh(Post post) {
em.refresh(post);
}
}
and
#Repository
public interface PostRepository extends CrudRepository<Post,Long>{
}

Using #Query witouht extends from JpaRepository

I am trying to execute system request using #Query. So, I do not have to extends JpaRepository and create an entity for no purpose.
I get this error:
Field myDAO in myPackage.impl.MyService required a bean of type 'myPackage.dao.MyDAO' that could not be found.
At MyService, I autowired MyDAO.
public class MyService implements IMyService {
#Autowired
private MyDAO myDAO;
#Override
public List<String> getAllTablesName() {
return myDAO.getAllTablesName();
}
}
I try to add #Repository but nothing is changed
#Repository
public interface MyService{
#Query(value ="SHOW TABLES FROM :tableName",nativeQuery = true)
public List<String> getAllTablesName(#Param("tableName") String tableName);
}
How can I solve this problem ?
While you do not have to extend JpaRepository you'll at least have to extend Repository
If you really don't have an entity you probably shouldn't use JPA in the first place which is all about mapping entities to database tables.
If you just want to execute statements a better fit might be a simple class with an injected JdbcTemplate or NamedParameterJdbcTemplate.

Spring Data JPA custom method causing PropertyReferenceException

I have been trying to create a spring boot application. In my application I would like to add some custom methods to save the data instead of using the default save method.
My application entry point is something like this:
#Configuration
#ComponentScan
#EnableJpaRepositories(repositoryImplementationPostfix = "CustomImpl")
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
#PropertySource("application.properties")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have changed this line repositoryImplementationPostfix to even Impl but, it didn't work.
My CrudRepository
#RepositoryRestResource
public interface TaRepository extends CrudRepository<Ta, Integer> ,TestRepository{
List<Ta> findByName(#Param("name") String name);
}
My Custom Repository:
public interface TestRepository {
public void myCustomMethod(TestDto dto);
}
My Custom Repository Impl
public class TestRepositoryCustomImpl implements TestRepository{
#PersistenceContext
private EntityManager em;
#Override
public void myCustomMethod(TestDto model){
}
NOTE:
If I change my CrudRepostory from the mentioned to this:
#RepositoryRestResource
public interface TaRepository extends CrudRepository<Ta, Integer> {
List<Ta> findByName(#Param("name") String name);
}
everything works fine. But not with the custom method implementation.
For Spring Data JPA #Repository or #RepositoryRestResource you never need to implement a Custom Interface. For any simple query you can create any kind of method, please follow the simple guide.
http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html
For a complex query you can use JpaSpecificationExecutor.
How can I create a Predicate from a HQL query?

How Spring creates an implementation of CrudRepository interface+CustomRepositoryInterface?

Hy,
I have the next code in Spring
#Repository
public interface UserRepository extends CrudRepository<User, String>,
UserRepositoryExtension<RosterUser> {
...any custom spring JPA methods...
}
Extension Interface:
public interface UserRepositoryExtension <T> {
public T put(T entity);
}
Implementation of Extension interface
public class UserRepositoryExtensionImpl implements
UserRepositoryExtension<User> {
#Autowired
EntityManager entityManager;
#Override
public User put(User user) {
entityManager.....(any logic here)
}...
}
I knew that Spring was able to create an inplementation of the UserRepository+CrudRepository interface methods in inyection time but what I dont get is:
how spring creates these implementations and combine them with my implementation of UserRepositoryExtensionImpl(what happens under the hood?)
How Spring knows what entityManager to use in the implementation class of UserRepository+CrudRepository it creates in injection time? It takes the entityManager from the context or from the class UserRepositoryExtensionImpl where an entityManager is declared?
Thanks

Resources