5

I have the following entities:

DummyA:

@Entity
@Table(name = "dummy_a")
@Data
public class DummyA implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dummy_b_name", referencedColumnName = "name", updatable = false, insertable = false)
private DummyB dummyB;
}

DummyB:

@Entity
@Table(name = "dummy_b")
@Data
public class DummyB implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "entity_id")
private Integer id;

@Column(name = "name")
private String name;
}

As it currently stands, any attempt to fetch DummyA objects results in additional queries to fetch DummyB objects as well. This causes unacceptable extra delay due to N+1 queries and also breaks Page objects returned by repository.findAll(specification, pageable), causing incorrect total page counts and element counts to be returned (in my case repository extends JpaRepository). Is there a way to do it such that DummyB objects are lazily loaded or, if that's not possible, so that they're all eagerly loaded in a single query?

Limitations: I'm fairly new to JPA and Hibernate and have been learning how to use them. I've come across the following in a project I'm working on. I don't have the liberty to include new dependencies and my project currently does not allow hibernate bytecode enhancement through @LazyToOne(LazyToOneOption.NO_PROXY).

Things I've tried so far and did not work / did not work as expected:

  1. @ManyToOne(optinoal = false, fetch = FetchType.LAZY)
  2. Tried to see if accessing the dummyB field in dummyA is what caused the N+1 queries by removing dummyB's setter and getter. Still had N+1 queries.
  3. Using @EntityGraph on findAll.
  4. Tried implementing PersistentAttributeInterceptable and using PersistentAttributeInterceptor to solve the problem.

Links to resources I've looked up so far:

  1. @ManyToOne(fetch = FetchType.LAZY) doesn't work on non-primary key referenced column
  2. N+1 query problem with JPA and Hibernate
  3. Hibernate lazy loading for reverse one to one workaround - how does this work?
  4. PersistentAttributeInterceptable
  5. JPA Entity Graph

Any help is greatly appreciated.

  • Your entity definitions look off to me, as I don't see a collection defined in either of the two sides of the one to many relationship. – Tim Biegeleisen Aug 22 '21 at 08:36
  • @TimBiegeleisen when I received the entities to work on them, the many-to-one relationship was defined as a unidirectional relationship from DummyA to DummyB. If I'm not mistaken, if it were bidirectional I'd end up having a Collection on the side of DummyB along with a one-to-many relationship, correct? (Side question: does a unidirectional many-to-one relationship even make sense?) – Ahmed Yehia Aug 22 '21 at 08:43

1 Answers1

1

I've come back with an answer in case anyone is curious. It turns out that some entries had an invalid "magic" value in the column used by DummyA as the foreign key to associate it with DummyB, causing Hibernate to execute separate queries for those null values in order to check if the association is truly not found (see this doc and this answer from a related question). I mistook those queries as N+1. The project also had an interceptor that extended Hibernate's EmptyInterceptor in order to modify queries that produced pages, resulting in incorrect counts if secondary queries were executed.