3

I'll try to include all the relevant bits of information without overloading with too much. I have this object (stripped of a lot of irrelevant stuff):

@Entity @Table(name = "RoutingAliases") public class RoutingAlias { private Queue queue; private Queue scheduleQueue; @ManyToOne @JoinColumn(name = "queue_id", referencedColumnName = "other_id") public Queue getQueue() { return queue; } @ManyToOne @JoinColumn(name = "schedule_queue_id", referencedColumnName = "other_id") public Queue getScheduleQueue() { return scheduleQueue; } } 

Note that "queue" and "scheduleQueue" refer to the same object type/table via different properties. Either or both could be NULL or not.

@Entity @Table(name = "Queues") public class Queue { private Long id; private Long queue private Long otherId; @Id @Column(name = "queue_id") public Long getId() { return id; } @Basic @Column(name = "queue") public String getQueue() { return queue; } @Basic @Column(name = "other_id") public Long getOtherId() { return otherId; } } 

I try to retrieve a list of all RoutingAliases from my DAO class:

return em.createQuery("SELECT ra FROM RoutingAlias AS ra " + "LEFT OUTER JOIN FETCH ra.queue AS q " + "LEFT OUTER JOIN FETCH ra.scheduleQueue AS sq ", RoutingAlias.class).getResultList(); 

The SQL that gets generated results in a LEFT OUTER JOIN between RoutingAliases and Queue tables with two references to Queues under different table aliases. In other words, the initial query returns all the details necessary to populate RoutingAlias.queue and RoutingAlias.scheduleQueue with a single query. But what happens is, after all the RoutingAliases are retrieved (there are about 1150 in the database), Hibernate then makes an additional 1150 queries to the Queues table - the 1+N query problem. The generated SQL is valid, and I can copy-paste into a SQL window and it works fine. I've stripped out every extra bit of code from the actual code until all I've left is the above properties and the above HQL/JPQL statement. If I remove the reference to one of the Queue properties (either of them), it results in a single query. If I put the second one back in, it goes back to 1+N queries. If I remove the "JOIN FETCH" from the query and put a @Fetch on the properties instead, it does 1+(N*2) queries. Frankly, I'm stumped, as this is such a simple case that I'm out of things to try.

The only odd thing about the situation is that the FK between RoutingAlias and Queue is NOT via the primary key on the Queue table, but another property in the Queues table, which shouldn't make any difference since, as mentioned, pulling a list of Routing Aliases with just one Queue relationship works just fine in a single query.

EDIT: If I retrieve a single instance of RoutingAlias, (using the find() method to retrieve by ID) the system will retrieve it, and associated objects, in a single SQL query.

1 Answer 1

1

It looks like a bug in Hibernate - I can reproduce this issue as well.

However it works fine if I change the type of scheduleQueue from Queue to Queue2 and create a copy of the entity Queue named Queue2 (leaving it mapped to the same table !)

You can extract a superclass from these two classes

I have struggled a lot with such issues and wrote a small library for checking the number of queries generated by Hibernate - you might find it useful: https://github.com/bedrin/jdbc-sniffer

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.