Spring Data JPA Repository CRUD Testing - spring-data-jpa

I'm playing around with the Spring Data Repository and have a question on writing CRUD tests. I have written many CRUD tests against Hibernate DAOs and EJB 3 entity beans where I create and entity, flush it to the database, clear the entity manager, and read it back by ID. The entity manager is cleared so the first level cache is not hit on the read.
Using the Spring Data repository I can't find a way to clear the underlying entity manager used by my test so my read is not going back to the actual database, making my test invalid.
Is there any way to clear the entity manager in the test? Is there a way I can inject one into my test so that it is used by the repository?
Thanks!
Cory.

Try it by injecting the entitymanager like this:
#PersistenceContext
EntityManager entityManager
and make your test transactional by setting the #Transactional attribute on your test method. Then inside the method you can call the entityManager.flush() method.
Regards

If you wish the EntityManager to be cleared automatically you can set #Modifying annotation’s clearAutomatically attribute to true.
Please see here

Related

Why are my entities only partially populated when loading them using Spring Data JPA?

I'm using Spring Data JPA and DataNucleus as JPA persistence provider and have something like
interface BookRepository extends CrudRepository<Book, Long> {
Book findByAuthorId(Long id);
}
If I call bookRepository.findByAuthorId() and then access book.publishingHouse.manager.name is null. As opposed to calling bookRepository.findAll() when the fields are populated correctly all the way. I set datanucleus.DetachAllOnCommit=true and datanucleus.maxFetchDepth=-1 (I also tried with 10).
Any idea why?
If you don't have any additional transaction boundaries defined, the EntityManager closed when leaving the query method. That means what you get back is detached entities and what kind of load state you get back is determined by the defaults the persistence provider uses.
You basically have two options:
Have a client (service or controller class) using #Transactional to keep the EntityManager open and thus the loaded instances eligible to lazy-loading to pull data out of the store while you use the instance. If a controller or service is not enough, you might wanna look into the OpenEntityManagerInViewFilter/-Interceptor which basically keeps the EntityManager open until the view is rendered.
Define what should be fetched explicitly either using JPA 2.1 entity graphs (see the reference docs for details) or explicitly adding fetch-joins to the query by defining it manually.

Spring Data JPA - Using #Transactional in a CDI environment instead of Spring environment

I realized after writing this question I could sum it up in a few sentences. How can I manage transactions in Spring-Data-JPA with CDI the same way you would by using #Transactional in Spring itself?
First thing I did was set up Spring Data JPA CDI based on the documentation here. http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/jpa.repositories.html#jpd.misc.cdi-integration
I set this up and it is working fine for read operations but not write operations
For Example, Their example in the docs would work fine.
List<Person> people = repository.findAll();
So I have the basic setup complete.
Written by hand may have typos. This is similar to the code I execute.
#Inject
UserRepository userRepository;
User user;
#Transactional
public void signUpUserAction() {
userRepository.saveAndFlush(user);
}
Then I receive this error
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
At first I realized I did not have the #Transactional so I added it and still did not work.(I believe in spring you need to use the AOP xml file to set up #Transactional so it makes sense this does not work in EE out of the box, I just do not know how to make it work.)
FYI annotating with this does not work
#TransactionAttribute(TransactionAttributeType.REQUIRED)
Something I tried while I was writing this post and I got it to work sort of... but I don't like the code and am still interested in using #Transactinoal, this code feels dirty, I'm pretty sure #Transactional handles calling other methods that are transactional in a clean way while this code would not.
This saves and I verify it's in the database.
#Inject
EntityManager em;
#Inject
UserRepository userRepository;
private User user;
public void signUpUserAction() {
em.getTransaction().begin();
userRepository.saveAndFlush(user);
em.getTransaction().commit();
}
So in short, how can I use #Transactional or something similar to manage my transactions?
Thank you for any help.
If you run Spring Data in a CDI environment, you're not running a Spring container at all. So you'll need to use EJB session beans to work with the repositories as CDI currently does not have support for transactions out of the box. The CDI extensions shipping with Spring Data is basically providing an entry point into the JavaEE world and you'll use the standard transaction mechanisms you can use in that environment.
So you either inject a repository into an #Stateless bean directly or you inject the CDI bean into one. This will allow you to use EJB transaction annotations on the EJB then.
for everyone who have this question yet.
I have this experimental project that support #Transactional in a CDI environment.
This project uses a custom code of Narayana as interceptor and provide compatibility with it and Spring Data Jpa implementation.
Key points to take in consideration:
Custom (Spring Data) Cdi Configuration -> add a Custom Transactional Post Processor custom spring data cdi configuration
Implement a custom Transactional Post Processor:
sample of a Custom Transactional Post Processor
Implement a custom Transactional Interceptor sample of a custom transactional interceptor
Add a Cdi Producer for your custom Tx Interceptor cdi producers
Create your custom repository fragments using #Transactional (JTA) custom fragments
Compose your Repository interface extending Repository interface and your fragments with #NoRepositoryBean annotation custom repositories
Take a look at this link that have some tips:
tips
Regards,

How to get a detached object from JPA

In my application I need most objects fetched in detached mode (fetched with the find API).
I'm wondering if there is a way to ask a detached object from the JPA provider and save the extra call to detach() API.
In additional I would expect the object created in such mode to be less expensive since the JPA provider doesn't need to add it to the entity manager context.
Is there a way to achieve this with JPA APIs?
Is there a way to achieve such functionality with query results?
Specifically I'm using Eclipse Link so if there is a specific way to do it with this implementation it will be helpful as well.
You can fetch a detached entity without an extra call to detach() if you fetch it outside a transaction. If you are not using container-managed transactions, it's trivial, simply do not start a transaction.
If you are using CMT, you have to make sure the requesting object is not a transaction-enabled EJB:
if in an EJB, suspend the transaction by annotating the appropriate method with:#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED),
or
call the EntityManager from a POJO. You dont have to call it directly, it only impotrant that the query result will end in a non-EJB object.
AFAIK, there is no performance gain to be expected, since the query result will always be put in the current persistence context, however shortlived it may be.
EDIT: There is another possibility to get detached objects which does not depend on transaction demarcations: JPA constructor expressions:
List<DTO> dtos = em.createQuery("SELECT NEW com.example.DTO( o.title, o.version) FROM Entity o").getResultList();
The constructed type must have a constructor with all the relevant attributes. The objects in the list, entities or not, will always be created detached. However there is a small overhead of instantiating a new object.

Auditing with Spring Data JPA

I am using Spring Data JPA in an application in which all entity objects need auditing. I know that I can have each either implement Auditable or extend AbstractAuditable, but my problem is coming with the overall auditing implementation.
The example on the Spring Data JPA reference pages seems to indicate that you need an AuditableAware bean for each entity. Is there any way to avoid this extra code and handle it in one place or through one configuration?
The generic parameter of AuditorAware is not the entity you want to capture the auditing information for but rather the creating/modifying one. So it will typically be the user currently logged in or the like.

JPA NamedQuery does not pick up changes to modified Entity

I have a method that retrieves Entities using a NamedQuery. I update a value of each entity and then run another named query (in the same method and Transaction) filtering by the old value and it returns the same Entities as if I had not changed them.
I understand that the EntityManager needs to be flushed and also that it should happen automatically but that doesn't make any difference.
I enabled hibernate SQL logging and can see that the Entities are not updated when I call flush but when the container transaction commits.
EntityManager entityManager = getPrimaryEntityManager();
MyEntity myEntity = entityManager.find(MyEntityImpl.class, allocationId);
myEntity.setStateId(State.ACTIVE);
// Flush the entity manager to pick up any changes to entity states before we run this query.
entityManager.flush();
Query countQuery = entityManager
.createNamedQuery("MyEntity.getCountByState");
// we're telling the persistence provider that we want the query to do automatic flushing before this
// particular query is executed.
countQuery.setParameter("stateId", State.CHECKING);
Long count = (Long) countQuery.getSingleResult();
// Count should be zero but isn't. It doesn't see my change above
To be honest I'm not that familiar with JPA, but I ran into similar problems with Hiberate's session manager. My fix was to manually remove the specified object from Hibernate's session before querying on it again so it's forced to do a lookup from the database and doesn't get the object from cache. You might try doing the same with JPA's EntityManager.
I've just had the same issue and discovered two things:
Firstly, you should check the FlushMode for the persistence context
and / or the query.
Secondly, make sure that the entity manager is
exactly the same object for both transaction management and query
execution. In my case, I had Mockito spy on the entityManager, which
was enough to break the transaction management.