cancel
Showing results for 
Search instead for 
Did you mean: 

SAP JPA and lazy loading

Former Member
0 Kudos

Dear experts,

I have a WD application with EJB model. I have faced strange JPA exception (I am using SAP JPA implementation).

This is 2 Entities with relationship

@Entity
@Table( schema = "dbo", name = "class")
public class ClassEntity {

  private Long id;
        @Id
	@Column(name="id")
	@GeneratedValue(strategy= GenerationType.IDENTITY)
    public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}

private Collection<ClassAttributeEntity> classAttributesById;

    @OneToMany(mappedBy = "classByClassId", fetch=FetchType.LAZY)
    public Collection<ClassAttributeEntity> getClassAttributesById() {
        return classAttributesById;
    }

    public void setClassAttributesById(Collection<ClassAttributeEntity> classAttributesById) {
        this.classAttributesById = classAttributesById;
    }

}

@Entity
@Table( schema = "dbo", name = "class_attribute")
public class ClassAttributeEntity{

private Long id;
        @Id
	@Column(name="id")
	@GeneratedValue(strategy= GenerationType.IDENTITY)
    public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}

    private ClassEntity classByClassId;

    @ManyToOne
    @JoinColumn(name = "class_id", referencedColumnName = "id")
    public ClassEntity getClassByClassId() {
        return classByClassId;
    }

    public void setClassByClassId(ClassEntity classByClassId) {
        this.classByClassId = classByClassId;
    }
}

I want to execute JPQL query

"SELECT c FROM ClassEntity c"

; But I get this exception:

javax.persistence.PersistenceException: The relationship >>classAttributesById<< of entity {test.ClassEntity(id=1686)}cannot be loaded because the entity is detached

I can overcome it using EAGER loading -

@OneToMany(mappedBy = "classByClassId", fetch=FetchType.EAGER)

, but I really dont need ClassAttributes in this situation! I have many thousands of classes and eager loading provides extremly poor perfomance. What can I do with this problem?

Thanks in advance for any advice.

Accepted Solutions (0)

Answers (5)

Answers (5)

0 Kudos

Hi Andrey,

I've encountered similar problems in a project I was working on.

I've fixed (worked around) this problem by creating an @AroundInvoke method that replaces everything lazily loaded with null. This

@AroundInvoke method is placed in an EJB that is inherited from by all my session beans.

It applies this procedure to the returned object:

  1. Check if the object is already processed.
    If so return;
  2. Check if the object is a collection
  3. If so, do the procedure for all elements.
  4. Else, call every getter (no params, no getClass())
    1. Check if the object is a "basic" object (primitive, enum, Date, Boolean, Number etc.)
      If so, continue with other getters;
    2. Check if the object is lazy loaded:
      1. Check if any interface is com.sap.engine.services.orpersistence.client.LazilyLoadable
      2. Check if a call to the isPending method returns true.
    3. If the object is lazy loaded call the corresponding setter with null.
    4. Else execute the procedure for the result.

It required a lot of tweaking, but eventually it solved the problem. Depending on the size of your codebase it's a lot less work than doing it manually for every return.

Steven

Former Member
0 Kudos

Hi Sergi!

Can you give me a link to a resource, where I can read more about that behaviour?

Thanks in advance.

Former Member
0 Kudos

Hi Andrey,

This is a consequence of Web Dynpro Models. When it is load a Web Dynpro model from an EJB call, the underlying EJB Model abstraction executes the entire model tree in order to map the entire tree to the corresponding context. This is the reason you get this exception.

Former Member
0 Kudos

"I assume you are getting the exception if you atempt to access "classAttributesById" ouside the transaction, in which you executed the query, i.e. after the persistence context, in which the query has been executed is closed."

Yes, you are right.

But I really access only name field of ClassEntity in my code. And I really need no ClassAttributeEntity.

Maybe WD itself tries to access all fields implicitly? EAGER is completely unacceptable for me((

adrian_goerler
Active Participant
0 Kudos

Hi Andrey,

I assume you are getting the exception if you atempt to access "classAttributesById" ouside the transaction, in which you executed the query, i.e. after the persistence context, in which the query has been executed is closed.

You have got to make sure that all entities you need to access are read as long as the persistence context executing the query is still open.

How to address this depends a bit on whether you need to access all related entites or only some.

If you need to access the relationship "classAttributesById" for only some instances of "ClassEntity", you could for example call size() on "classAttributesById" for these selected instances of "ClassEntity" (within the same transaction/persistence context".

If you need to access all related entities, theoretically, fetchType = EAGER would be the right choice. However, as you have observed, SAP JPA can't handle this efficiently at the time beeing. Therefore,

I'd rather suggest that you firstly load all related attributes with a query

"SELECT ca FROM ClassAttributeEntity ca"

and secondly load the "ClassEntity"s

"SELECT c FROM ClassEntity c"

this should execute efficiently.

Sorry for the inconvenience.

-Adrian