20

From my understanding @OneToOne and @ManyToOne JPA annotations do an eager fetch. I want these to be lazily loaded in my application, or at least hint at it (which is what hibernate defaults to). I have started to add the annotation fetch = FetchType.LAZY

eg

@ManyToOne(optional = false, fetch = FetchType.LAZY)

instead of

@ManyToOne(optional = false)

This is both tedious and error prone. Is there a way I can do this at an application level? In the persistence.xml perhaps?

Perception
  • 75,573
  • 19
  • 170
  • 185
RNJ
  • 14,308
  • 16
  • 73
  • 125

4 Answers4

19

To date, I have chosen to have Hibernate follow the JPA spec in terms of mapping via annotations simply because I have not received any feature requests for making it configurable, which was surprising TBH. As you point out, since Hibernate 3.0 what you want has been the default set up when using hbm.xml mapping files.

Allowing this via configuration would not violate the spec as another answer suggested.

So long story short, no it is not possible today. Create a feature request if you'd like to see that be configurable.

FelipeAls
  • 20,411
  • 7
  • 49
  • 71
Steve Ebersole
  • 8,735
  • 2
  • 42
  • 44
6

JPA Spec assumes that in general most of the applications will require the singleton relations by default be eager, whereas multi value relations by default be lazy. And at least in my own experience, this is generally the desired architecture. This makes sense, since singleton relations require no significant additional performance in JPA layer and DB layer to create a singleton join on foreign key. However, in contradiction to that, multi valued attributes create either N + 1 problem or large cartesian resultsets that get inflates exponentially as the number of elements in collections and number of joins increase when join fetch is used (Although Hibernate specifically cannot handle join fetches on 2+ eager associations).

Having said that, as for your suggestion, you require a specific (to be honest not completely uncommon) case to be addressed. Now you have a single case but as there are hundreds of cases like that. So to write specifications you need to draw a line between the generalization and granularity.

If I were in your shoes, if you think this an absolutely useful feature to be added to JPA Specification, I would submit it to the JCP. On the other hand if you get this(, that and that...) addressed in a specific implementation then you end up in so-called vendor-lockin. So I would work an extra hour to set the lazy fetch on @ManyToOne @OneToOne attributes and stay vendor-free, therefore by sticking to the specification if say a new JPA implementation comes along that is over 15x faster then Hibernate (or whatever implementation you use), it would take little to no effort to move your project that new JPA implementation.

Hasan Ceylan
  • 581
  • 3
  • 7
  • 2
    You are totally mistaken that "Hibernate specifically cannot handle join fetches on 2+ eager associations". That is completely false. – Steve Ebersole Oct 08 '12 at 17:23
  • You may want to google "org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags" – Hasan Ceylan Oct 09 '12 at 06:17
  • To clarify, your statement above throws a blanket that Hibernate is not able to perform "join fetches on 2+ eager associations". The false implication is clear, that Hibernate somehow cannot eager fetch multiple of any type of association. Yet the reality is that, yes, it cannot join fetch multiple types of associations not even defined by JPA.. ok... – Steve Ebersole Oct 09 '12 at 13:28
  • 2
    @Steve, I am not a native English speaker, nor I would like to create a false critic based on made-up-facts. If the phrase is wrong, please feel free to correct or suggest a correction so I will update my answer. – Hasan Ceylan Oct 10 '12 at 06:05
3

no way. there is nothing about changing global fetching strategy in JPA specification. JPA offers for 1-1/N-1 associations EAGER fetching, whereas for 1-N/M-N it is LAZY. All JPA implementations should follow the specification to be compliant. I think, it is better that the application developer can't change this default beheavior globally, since these are the best practices in almost most cases unless you've just one type of association between all entities, like 1-1. think about, that you could set it to "EAGER" in an application, which contains a really rich entity model with complex relations and millions of data in the database. Overriding the fetching strategy per association manually allows the developer to take the responsibility about what will next happen. it is not error prone, instead, a powerful feature.

Erhan Bagdemir
  • 5,003
  • 6
  • 27
  • 39
  • You use one-to-one to justify this, yet many-to-one is *by far* the more common type of association. Yes, eager fetching is probably better in the case of one-to-one associations. The reason it is better to have laziness as the default really has more to do with the fact that there are plenty of well-defined ways to make associations eager at runtime (in both Hibernate and JPA), but almost no ways to explicitly make them lazy. – Steve Ebersole Oct 02 '12 at 14:39
  • How is one-to-one and many-to-one are different in that context, how one justifies yet the other one fails to justify? I strongly think that Erhan has a point in that. If you have a product, yet the customer wants to use it with a different JPA implementation. Then either they will end up with inconsistency or they will have to modify the original code to make it compatible with the other implementation. Yet you are totally right in saying impossible to turn a relation into lazy at runtime. – Hasan Ceylan Oct 09 '12 at 06:39
  • Because experience says that one-to-one relationships are far more frequent than many-to-one as I already pointed out above. You are being idealistic; I am being pragmatic. I prefer real-world solutions – Steve Ebersole Oct 09 '12 at 13:25
  • Of course that should read "... one-to-one relationships are far *less* frequent than many-to-one ..." ;) – Steve Ebersole Oct 09 '12 at 13:49
  • OK, That last comment clarifies that. It is not about being idealist but was an objection to the form of the earlier version of your comment... :) – Hasan Ceylan Oct 10 '12 at 06:00
1

From my understanding @oneToOne and @ManyToOne JPA annotations do an eager fectch.

JPA guarantees eager-loading on single-valued relationships, if not otherwise declared by annotation or within the persistence XML. For Collection-valued relationships it defaults to lazy loading, but lazy loading is (just) a hint to the persistence provider supporting JPA, so you cannot rely on it, and have to check for the specific provider (e.g. Hibernate, OpenJPA). See this link as a reference, and for more insight.

Felix Dobslaw
  • 383
  • 4
  • 13