4

I am facing an issue where the data is getting fechted recursively. I wanted to avoid the child to fetch the parent data. Which is causing a recursive issue. I have mentioned the code below

Pojo Structure

class Parent  {
    ..
    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    private List<Child> childs;

    ..
    }

class Child {
    ..
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parentId")
    private Parent parent;
    ..
    }

Fetching the data like this

 `  em = EMF.get().createEntityManager();
    Query q = em.createQuery("Select p from Parent p", Parent.class);
    List<Parent> parents = q.getResultList();
    // Till this point all looks good but when the code gets executed 
    parent.getChilds();
`

It is fetching the data like this:

Parent
child1
    Parent
        child2
            Parent
                child2
                    Parent
                ..
        ..
child2
..

Which I dont need I just want the data like this:

Parent1
    child1
    child2
Parent2
    child1
    child2
    child3
  • By Default default fetch mode is lazy – soorapadman May 24 '17 at 15:24
  • @soorapadman by default, fetching is lazy for to-many and eager for to-one relationships – crizzis May 24 '17 at 15:26
  • What provider? Lazy fetching of OneToOne/ManyToOne is provider specific and may require something more depending on your environment. EclipseLink for instance requires weaving https://www.eclipse.org/eclipselink/documentation/2.5/concepts/app_dev007.htm – Chris May 24 '17 at 18:00

4 Answers4

3

While FetchType.EAGER is a contract, FetchType.LAZY is only a hint, because lazy fetching is not always possible. This may depend e.g. on the JPA provider you use as well as on its configuration. Lazy fetching is particularly problematic with to-one relationships.

If every Child has a Parent, try adding optional=false to your @ManyToOne. This might enable lazy fetching.

Since the Parent entity is already loaded into the persistence context, populating Children.parent shouldn't trigger queries against the database. Are you actually seeing queries being executed? How do you know Children.parent is being loaded? If you are accessing the value to check that fact, chances are you are actually triggering the on-demand loading yourself.

crizzis
  • 9,978
  • 2
  • 28
  • 47
  • If every Child has a Parent, try adding optional=false to your @ManyToOne. This might enable lazy fetching. It didnot work How do you know Children.parent is being loaded? I need to execute parent.getChilds(); and when I am doing it I can see the parent object in it and in this parent there is a child object as so on. you can get an idea by looking into : https://drive.google.com/file/d/0B_A6oOU92Jt8M2pGZlpaQ3RuQTA/view?usp=sharing –  May 24 '17 at 15:32
  • OK. As I said, this is not a performance issue, because the `Parent` entity is already present in the persistence context, so the `Parent` lookup for children does not hit the database. If you want lazy loading nonetheless, are you using JPA in Java SE or Java EE? For lazy loading to work with to-one relationships, you need to enable weaving (see: http://www.eclipse.org/eclipselink/documentation/2.6/concepts/mappingintro002.htm#CEGCJEHD and the paragraph just above it) – crizzis May 24 '17 at 15:54
  • we are having Java EE and EclipseLink, version: Eclipse Persistence Services - 2.0.2.v20100323-r6872. Yes its not an performance but the application is getting hang. The reason is, since its a bidirectional relationship when we are fetching the child its fetching the parent as well which again set the child having a parent inside it. This is causing the server to hang because the circular values. –  May 25 '17 at 08:34
  • I'm not sure EclipseLink alone could cause an infinite loop here, since it would be a serious bug for a fairly common use case. Are you sure `parent.getChilds()` is the source of the problem? Can you see other methods in the stack trace (I understand you're ultimately getting a `StackOverflowError`)? The fact that you managed to inspect the value of `Parent.getChilds()` using the debugger suggests that loading children completed successfully, and the error is caused by some other code executed later on... – crizzis May 25 '17 at 10:20
  • There is neither StackOverflowError or any other exception. The issue is it is taking time of more then 1 minute which results in our server time out. We need to get the result with in one minute of time. If we increase the server time out it will work fine. –  May 25 '17 at 12:10
1

It'll work as infinite loop for hefty data. Best practice is to mention @JsonIgnore at child class column. Thank me Later

Divvy Vyas
  • 11
  • 1
1

To avoid this problem of cyclic references, I used a Mapper with MapStruct (see official documentation for a quick setup) :

Then I can easily write a mapper to ignore a property like this :

public interface SecondaryObjectMapper {
  @Mapping(target = "primaryObject.secondaries", ignore=true),
  SecondaryObjectDto toSecondaryObjectDto(SecondaryObject source);
}

and use it like this for example :

repository.findAll(pageable).map(secondaryObjectMapper::toSecondaryObjectDto)
DependencyHell
  • 1,027
  • 15
  • 22
0

To Avoid this issue , Please declare below annotation Parent & Child getter methods

   @JsonBackReference
    public Parent getParent() {
        return parent;
    }

@JsonManagedReference
    public List<Child> getChilds() {
    return childs;
    }
  • 1
    You might want to describe a little more too why this solves the issue in the question, and not just paste some code. :) – Qben Jun 15 '20 at 13:56