9

I've seen several similar questions with 0 good answers.

This should be very simple. I'm using Java JPA and I want to load a List of child entities sometimes but not all the time. Unfortunately, JPA doesn't seem to be listening to me when I say to fetch it lazily. I've made 100% certain that there's nowhere in my code where the childEntities attribute is being accessed in any way. However, all the child entities are still getting loaded immediately upon my JPA.em().find(..) call. This is how I declare the relationship with annotations.

@Entity
@Table(name = "parentEntities")
public class ParentEntity implements Serializable {
    ....
    @OneToMany(mappedBy = "entityPropertyName", fetch = FetchType.LAZY)
    public List<ChildEntity> childEntities;
    ...
}

And this is how I load the parent entity:

ParentEntity parentEntity = JPA.em().find(ParentEntity.class, id);

Additionally, I was hoping to sometimes eager fetch this collection and be able to dynamically tell JPA when to do so. That's step 2 though. Step 1 is just to get this working right.

Cameron Askew
  • 1,373
  • 1
  • 9
  • 20
  • 1
    How are you verifying that it is fetched? Is there an orm.xml or other place mappings or entity listeners might be set that either override the lazy setting or trigger the collection? What provider are you using? – Chris Jul 28 '13 at 00:00
  • In the debugger I can see right after the find call that the list is populated. I'm not using any XML for configuration, only annotations. – Cameron Askew Jul 28 '13 at 00:41
  • For now I've created an extremely bloated and hacky solution. I've created two parent entities, one with the child list collection and one without. Unfortunately, this hack (as many hacks do) cascades filth into the rest of my code. – Cameron Askew Jul 28 '13 at 00:45
  • 1
    What provider are you using, and has this entity been previously loaded such that the relationship might already have been fetched? Try an em.refresh after the find and see it the relationship is untriggered, and also make sure your debugger isn't triggering the list - they type of the list and how it is triggered might be provid specific – Chris Jul 28 '13 at 02:30
  • I'm using JPA, not Hibernate or anything if that's what you mean. I don't think the debugger was generating it..whether or not I attached the debugger process, I was getting the same results, I was only prompted to use the debugger because of the strange results. As for the em.refresh(), I'm a bit far down the rabbit hole with the hacked solution to want to revert back and try, I guess I should have versioned the code at that point but I just kept on. – Cameron Askew Jul 28 '13 at 03:04
  • Also, I'm sure the entity wasn't previously loaded. – Cameron Askew Jul 28 '13 at 03:13
  • There definitely could have been the case where I had an issue, fixed it and attached a debugger, but the debugger caused the fix not to work because it was now generating the list. Good point. I am too scared to change it all back now though lol – Cameron Askew Jul 28 '13 at 03:15
  • 1
    JPA is a specification, while hibernate, EclipseLink etc implement the spec. You are using an implementation, and it matters which one. You don't need to change anything other than try the refresh. If it works, then we know your provider supports lazy and something like the entity being preloaded is occurring. – Chris Jul 28 '13 at 20:32
  • I believe I'm using Hibernate then...I'm using Play framework and [here](http://www.playframework.com/documentation/2.1.1/JavaJPA) is the guide I used to get started. I'll try the refresh when I get some free time this week. Thanks again. – Cameron Askew Jul 29 '13 at 23:11

2 Answers2

5

I have done in this way. Please refer this, it will be working excellently overthere too:

@Entity
@Table(name = "member_information")
    public class MemberInformation  implements Serilizable{

     @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE},optional = false)
        private MemberInformationDetails memberInformationDetailsId;


     @LazyCollection(LazyCollectionOption.TRUE)
        @OneToMany(mappedBy = "memberInformationId", cascade = CascadeType.ALL)
        private Collection<AccountOpening> accountOpeningCollection;


    }

Use @OneToOne(fetch = FetchType.LAZY....) for one to one mapping and for collection use @LazyCollection(LazyCollectionOption.TRUE).

@Entity
@Table(name = "member_info_details")
public class MemberInformationDetails implements Serializable{

@OneToOne(mappedBy = "memberInformationDetailsId")
    private MemberInformation memberInformationId;

.......//getter and setters

}


@Entity
@Table(name = "account_opening")
public class AccountOpening  implements Serializable {

 @JoinColumn(name = "member_information_id", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private MemberInformation memberInformationId;

..........//getters and setters

}

When you want to access the collection ,merge before and get the object:

@Stateless
public class MemberInformationFacade{
..............
  public MemberInformation getMemberWithMemberDetails(MemberInformation m) {
        m = getEntityManager().merge(m);
        try {
            m.getMemberInformationDetailsId().getId();


            m.getMemberInformationDetailsId().accountOpeningCollection().size();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return m;
    }

}
Magnilex
  • 10,219
  • 8
  • 49
  • 72
Rajesh
  • 138
  • 8
3

I'm actively looking for the answer to your #2: getting JPA to lazy load stuff sometimes and eagerly other times.

As for your #1 question it sounds to me that you want is to use getReference() instead of find(). If you're using Hibernate then it will create a reference of the object and then only actually get it when it's needed.

I'm sure this will help: When to use EntityManager.find() vs EntityManager.getReference()

Community
  • 1
  • 1
Alan B. Dee
  • 4,982
  • 4
  • 31
  • 28