1

I have two classes InvitedPerson and Flight with a one to one relationship with each other. Here is how they are annotated.

public class InvitedTech{
    ...
    @OneToOne(mappedBy="invitedTech", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    public Flight flight;

    @OneToOne(mappedBy="invitedTech", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    public Hotel hotel;

    ...
}

public class Flight{
    ...
    @OneToOne
    @JoinColumn(name="invitedTechId", nullable=false)
    public InvitedTech invitedTech;
    ...
}

As you can see Flight is the owner of the relationship and InvitedTech is the other side of this bidirectional relationship. InvitedTech also has a OneToOne relationship with Hotel Now, when I write a simple query to fetch all flights, it triggers three queries in total. 1st which gets me the results, but fires 2 additional queries.

List<Flight> flg = JPA.em().createQuery("SELECT flg from Flight flg").getResultList();
  1. Query that gets all flights (This is the only one that I need)
  2. Query with a join between InvitedTech and Flight
  3. Query with a join between invitedTech and Hotel

Why are query 2&3 being executed even though I have set FetchType=Lazy. I am not accessing Hotel Information. And Flight should not be queries again as the first query returns the data.

After some playing around when I remove mappedBy attribute from both the annotations, those 2 addition queries don't get executed(i.e only 1st gets executed).

Why does the mappedBy attribute cause additional queries to be executed even though FetchType=Lazy. Is there a way to stop this?

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
SpartanElite
  • 594
  • 3
  • 11

2 Answers2

2

I believe this is due to one of Hibernate's idiosyncrasies:

non-optional one-to-one relationships are eagerly loaded regardless of whether they are mapped as Lazy.

The reasoning behind this is that as the engine has to look in the association table anyway - to determine whether it should set the association as a proxy or as null - then it may as well load the associated entity anyway.

I have experienced this myself and as far as I know the only way round it is to mark the relationship with optional=false which tells Hibernate it can always set a proxy.

If the relationship is optional then the only other option seems to be byte code instrumentation.

See also:

https://community.jboss.org/wiki/SomeExplanationsOnLazyLoadingone-to-one

Making a OneToOne-relation lazy

Community
  • 1
  • 1
Alan Hay
  • 20,941
  • 2
  • 47
  • 97
0

You have not set the association from Flight to InvitedTech lazy. So it loads the InvitedTech associated with the flight.

Since it can't know from the InvitedTech if there exist a Hotel and a Flight associated with the InvitedTech, it can't decide if these fields should be null or should be proxies. So it's forced to execute additional queries to know if a hotel/flight exists for the InvitedTech.

JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
  • I have purposely set Flight to invitedTech as not lazy as I would like to get invitedTech details on flight access. Why is it doing the additional query for Flight even though the previous query access the invitedTech? Also is there way to stop those two queries from being executed until they are accessed ? – SpartanElite Nov 19 '13 at 15:17
  • If the association is non-optional, then mark it so. Otherwise, IIRC, it's possible to instrument your entities at compile-time and to annotate the association with LazyToOne(NO_PROXY), but I've had bad experiences with that previously. Maybe it's all working fine now. – JB Nizet Nov 19 '13 at 15:44