#ManyToOne(fetch=FetchType.LAZY) lazy loading not working - jpa

I am working with JPA 2.1 (EclipseLink 2.5.1) and JBoss 7.1.
I've define very simple JPA entities:
#Entity
#Table(name="APLICACIONES_TB")
public class Aplicacion implements Serializable {
#Id
#Column(name="COD_APLICACION_V")
private long codAplicacionV;
#Column(name="APLICACION_V")
private String aplicacionV;
#OneToMany(mappedBy="aplicacion")
private Collection<Prestacion> prestaciones;
... getters and setters
}
#Entity
#Table(name="PRESTACIONES_TB")
public class Prestacion implements Serializable {
#Id
#Column(name="COD_PRESTACIONES_V")
private String codPrestacionesV;
#Column(name="DESCRIPCION_V")
private String descripcionV;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "COD_APLICACION_V")
private Aplicacion aplicacion;
... getters and setters ...
}
I have developed a staless EJB that executes a query to obtain some "Aplicacion" entities.
#Stateless
#LocalBean
public class DocuEJB implements DocuEJBLocal
{
#PersistenceContext(name="DocuEjb", type=PersistenceContextType.TRANSACTION)
private EntityManager em;
public Prestacion getResult(String name)
{
return em.createNamedQuery("ExampleQueryName", Prestacion.class).getSingleResult();
}
}
Because I'm working with JSF 2.1 the EJB is being injected in a managed bean:
#ManagedBean(name = "ManagedBean")
#RequestScoped
public class ManagedBean
{
#EJB DocuEJB docuEjb;
public String doSomething()
{
Prestacion entity = docuEjb.getResult("egesr");
if (entity != null)
{
// It should return null because 'entity' should be detached
Aplicacion app = entity.getAplicacion();
// but 'app' entity is not null, ¿why not?
System.out.println (app.getCodAplicacionV());
}
}
}
Lazy loading is not working even when lazy loading has been defined for 'aplicacion' field on 'Prestacion' entity. The code posted before should return a NullPointerException in the next line:
System.out.println (app.getCodAplicacionV());
because 'app' entity is detached and lazy loading has been configured.
Why is not working lazy loading?
Thanks

Try to add #Transactional on doSomething(), I think that your transaction manager is not well configured.
You can see here the official spring documentation. In any case, can you add your spring configurations, so that we can better help you. :)

I don't think the behavior your encounter is abnormal or your question should state it clearly:
EJB are by default transactional
Your JSF inject an EJB, with #EJB, and I guess JBoss can create a java reference and not a proxy
The entity is being managed because the transaction is not done, it will finish when doSomething ends.
Your entity is then loaded into the EntityManager, and lazy loading works because there is a context to it.
You would call em.evict(entity) with the result your are getting, this would probably fails because the entity would not be managed any more.

Related

Upgrading from Spring Data 1.11 to Spring Data 2.0 results in "No property delete found for type SimpleEntity!"

I have a simple project with the classes below defined. It works just fine in spring-boot 1.5.4, spring-data-commons 1.13, and spring-data-jpa 1.11.
When I upgrade to spring-boot 2.0.0.M5, spring-data-commons 2.0.0 and spring-data-jpa-2.0.0, I get a PropertyReferenceException at startup that says "No property delete found for type SimpleEntity!" Unfortunately, I can't get the stack trace out of
the computer I get the error in, it is very locked down for security.
Any ideas? Other posts I found don't seem to match my situation.
Here are the classes (altered the names, but you get the idea):
package entity;
#MappedSuperclass
public abstract class BaseEntity implements Serializable {
....
}
package entity;
#Entity
#Table(schema = "ENTITIES", name = "SIMPLE")
public class SimpleEntity extends BaseEntity {
#Column(name = "ID")
private Long id;
#Column(name = "CODE")
private String code;
#Column(name = "NAME")
private String name;
... getters and setters ...
}
package repository;
imoport org.springframework.data.repository.Repository
public interface SimpleRepository extends Repository<SimpleEntity, Long> {
public SimpleEntity save(SimpleEntity entity);
public List<SimpleEntity> save(List<SimpleEntity> entities);
public void delete(Long id);
public SimpleEntity findOne(Long id);
public List<SimpleEntity> findAllByOrderByNameAsc();
public List<SimpleEntity> findByCode(String code);
public List<SimpleEntity> findByNameIgnoreCaseOrderByNameAsc(String name);
}
Turns out there is a breaking change in Spring Data 2.0 CrudRepository interface. The error I received occurs under the following conditions:
You have a 1.x Sping Data project
You have an interface that extends Repository directly, not a subinterface like CrudRepository
Your Repository subinterface declares the "void delete(ID)" method found in CrudRepository (in my case "void delete(Long)"
You update to Spring Data 2.x
The problem is that CrudRepository in 2.x no longer has a "void delete(ID)" method, it was removed, and a new method "void deleteById(ID)" was added.
When Spring data sees a delete method signature it doesn't recognize, it produces an error about your entity class missing a delete property - this is true of both 1.2 and 2.x.

Extended Persistence Context with ViewScoped CDI beans

I am a long time Seam user who tries to move to Java EE7, JSF2.2 and CDI now.
In Seam you tend to use EntityManagers with extended scope most of the time (in the Seam Conversation Scope). You don't get any LIEs on Ajax request etc.
I am trying to do it in a similar way with Java EE7 and CDI but somehow the injected EntityManager is only transaction scoped. When I get a ajax request in the entities that were loaded before are not managed anymore.
I am using the new javax.faces.view.ViewScoped and javax.transactional.Transactional on my CDI bean.
My Producer:
#PersistenceContext(unitName = "primary", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#Produces
#Default
#Dependent
public EntityManager getEntityManager() {
return entityManager;
}
And my CDI bean:
#Named
#ViewScoped
#Transactional
public class TestBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Inject
EntityManager entityManager;
Logger log = Logger.getLogger(TestBean.class);
private TestEntity lastTest = null;
public void testAdd(){
TestEntity test = new TestEntity();
test.setVal("Test "+System.currentTimeMillis());
entityManager.persist(test);
entityManager.flush();
log.infov("Created test entity {0}", test);
lastTest = test;
}
public void testRead(){
List<TestEntity> test = entityManager.createQuery("select t from TestEntity t").getResultList();
for(TestEntity t: test){
log.infov("Found {0} managed {1}",t,entityManager.contains(t));
}
if(lastTest!=null){
log.infov("Last Test {0} managed {1}",lastTest,entityManager.contains(lastTest));
}
}
So when I first call testAdd() via Ajax it creates a new test entity. When I then call testRead() it gets all test entities and checks that the last created test entity is still managed (which it should if it is an EntityManager with an extended persistent context). But entityManager.contains(lastTest) always returns false.
What am I doing wrong?
I believe I can't use #PersistenceContext directly in the CDI bean. So how do I get the desired (Seam like) behaviour?
When you specify that an injected EntityManager is an extended persistence context, all object instances remain managed. Extended persistence contexts can only be used within Stateful session beans.
This is according to JBOSS documentation: https://docs.jboss.org/ejb3/app-server/tutorial/extended_pc/extended.html.
Consider packaging your insert/update/delete operations into EJBs while simple read from database can be through CDI beans. But more complex operations involving multiple reads and writes as well as transaction should be within EJBs.

How to assign an #EntityGraph annotation to Spring Data JPA repository .findAll()

Annotating the Spring Data JPA repository method findAll() with #EntityGraph:
import org.springframework.data.jpa.repository.JpaRepository;
[...]
public interface OptgrpRepository extends JpaRepository<Optgrp> {
#EntityGraph(value = "Optgrp.sysoptions")
List<Optgrp> findAll();
}
leads to this error message:
org.springframework.data.mapping.PropertyReferenceException: No property findAll found for type Optgrp!
Same error happens when changing findAll() to other names:
findAllWithDetail() --> No property findAllWithDetail found for type Optgrp!
findWithDetailAll() --> No property findWithDetailAll found for type Optgrp!
Question: Is it at all possible to use the #EntityGraph annotation on a Spring Data JPA repository method that finds all entities?
EDIT: as asked in the comment, here's the extract from the Optgrp entity class:
#Entity
#NamedEntityGraph(name = "Optgrp.sysoptions", attributeNodes = #NamedAttributeNode("sysoptions"))
public class Optgrp implements Serializable {
[...]
#OneToMany(mappedBy="optgrp", cascade = CascadeType.ALL, orphanRemoval=true)
#OrderBy(clause = "ordnr ASC")
private List<Sysoption> sysoptions = new ArrayList<>();
}
And the Sysoption entity class as well:
#Entity
public class Sysoption implements Serializable {
[...]
#ManyToOne
#JoinColumn(name = "optgrp_id", insertable=false, updatable=false)
private Optgrp optgrp;
}
For all, who are using Stack Overflow as knowledge database too, I record a new status to Markus Pscheidts challenge. Three years and six months later the #EntityGraph annotation works now directly at the findAll() function in Spring Data JpaRepository, as Markus original expected.
#Repository
public interface ImportMovieDAO extends JpaRepository<ImportMovie, Long> {
#NotNull
#Override
#EntityGraph(value = "graph.ImportMovie.videoPaths")
List<ImportMovie> findAll();
}
Versions used in the test: Spring Boot 2.0.3.RELEASE with included spring-boot-starter-data-jpa.
Using the name findByIdNotNull is one way to combine both findAll() and entity graph:
#EntityGraph(value = "Optgrp.sysoptions")
List<Optgrp> findByIdNotNull();

PersistenceContext propagation and transaction spanning multiple EJBs in EJB 3.x

In our web application, we have a facade EJB which in turn calls multiple EJBs to perform a business function. The flow is like :
SLSB facade -> invokes ejb1, ejb2, ejb 3 etc -> invoke JPA layer
In each of the ejbs in the business layer, i inject entity manager using #PersistenceContext.
A simplified version of the code is as below:
#Stateless
public class facade{
#EJB
private EJB1 ejb1;
#EJB
private EJB2 ejb2;
#EJB ejb3;
private EJB3 ejb3;
public void performAction(..) {
// invoke method on ejb1
// invoke method on ejb2
// invoke method on ejb3
}
}
#Stateless
public class EJB1 implements IEjb1 {
#PersistenceContext(unitName = "pu")
private EntityManager entityManager;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public xxxEntity insert(xxxEntity entity) throws AppException {
// code for persisting the entity
}
}
#Stateless
public class EJB2 implements IEjb2 {
#PersistenceContext(unitName = "pu")
private EntityManager entityManager;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public yyyEntity insert(yyyEntity entity) throws AppException {
// code for persisting the entity
}
}
The application is deployed on Glassfish and uses JTA transaction. Since this is container managed PC, will the same persistence context be propagated to all EJBs? Will they run in the same transaction (reusing the transaction started in EJB1)? Is there a way to verify if the same transaction is used by all EJBs (same transaction id?)
By default all ejbs (1,2,3) will participate in the one, same transaction that is started by facade ejb. You would need to define different transaction attribute for them to use different transactions (e.g. REQIRES_NEW to create new transaction).
If you really need transaction id, you could try to inject TransactionSynchronizationRegistry into your bean like this
#Resource
TransactionSynchronizationRegistry registry;
// and then get key
...
registry.getTransactionKey()
See TransactionSynchronizationRegistry and Container-Managed Transactions

Entity states between EJB and Jersey

I'm a novice.
Does Jersey and EJB hold the same EntityManager scope?
Should I have to pass the EntityManager to EJB for same persistence context?
The primary target usage is JTA.
#Stateless
class MyEJB {
public MyEntity find(Long id) {
...
}
#PersistenceContext;
EntityManager entityManager;
}
class MyResource {
#GET
#Path("/myentity/{id}");
public MyEntity get(#PathParam("id") final long id) {
final MyEntity found = myEjb.find(id);
// is found's state detached?
// should I have to reattach?
found.setDate(new Date());
return found;
}
#EJB
private MyEjb myEjb;
#PersistenceContext;
EntityManager entityManager;
}
Does Jersey and EJB hold the same EntityManager scope?
Should I have to pass the EntityManager to EJB for same persistence context?
I don't think that your wording is correct, but they can share the same EntityManager instance, and you have chosen the right way (through injection). Have a look at this chapter of the Java EE 6 Tutorial:
To obtain an EntityManager instance, inject the entity manager into the application component:
#PersistenceContext
EntityManager em;
So, once again, your approach is correct. With regards to the questions in the code comments: the fact that MyEntity is attached or detached, it depends on the implementation of the find method in your EJB. If you do the following, it will be attached:
public MyEntity find(Long id) {
return entityManager.find(MyEntity.class, id);
}
Finally, doing this way, if you have chosen JTA to use container managed transactions, the transactions will be automatically bounded with the natural boundaries of MyBean's methods. In order to have JTA transactions, you have to use this line in persistence.xml file:
<persistence-unit name="em" transaction-type="JTA">