EntityManager getReference() vs find() APIs

Learn to get the proxy reference of an entity using the EntityManager#getReference() method and it’s difference with find() method in runtime.

1. EntityManager.getReference() Method

We know that in hibernate lazy loading can be done by specifying “fetch= FetchType.LAZY” in hibernate mapping annotations. In given example, competition will loaded lazily when the getCompetition() accessor will be invoked by the application code.

@Entity
public class Nomination {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;

  @ManyToOne(fetch = FetchType.LAZY)
  private Competition competition;

  //Getters and setters are hidden for brevity
}
@Entity
public class Competition {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String title;

  //Getters and setters are hidden for brevity
}

This kind of lazy loading applies to cases when we are defining the mapping between two entities where we apply one of the association mapping annotations.

But, what if we want to lazy load the enclosing entity itself we can use the getReference() API. It returns only returns an entity Proxy which only has the identifier set. If we access the other fields in the Proxy, the associated SQL statement will be triggered as long as the EntityManager is still open.

For example, if we want to persist a new Nomination for an existing Competition then we don’t need to fetch the Competition entity from the database. We only need the reference of an existing Competition.

Competition competitionRef = em.getReference(Competition.class, 1L);

Nomination nomination = new Nomination();
nomination.setName("Test");
nomination.setCompetition(competitionRef);

em.persist(nomination);

Now check the SQL queries executed for above example. No SQL SELECT query has been executed.


Hibernate: insert into Nomination (id, competition_id, name) values (default, ?, ?)

The getReference() is an excellent choice where we don’t need to load the entity and only need the entity reference with the primary id field set to it. This helps in situations where we need the entity just for setting the foreign key while executing the persist() operation.

Be careful in cases where the primary key may not exist. In these cases, persistence context will not throw any exception until we access one of the fields in the entity. If primary key is absent from database while accessing a field from reference entity, we will get the ConstraintViolationException exception in runtime.

For example, if Competition id 2 does not exist in the database then while persisting the nomination we will get Referential integrity constraint violation error.

//No error in this statement
Competition competitionRef = em.getReference(Competition.class, 2L);

Nomination nomination = new Nomination();
nomination.setName("Test");
nomination.setCompetition(competitionRef);

//Error comes while accessing competition
em.persist(nomination);
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: 
Referential integrity constraint violation: "FK7F1QFQ1Y14WSAGUOTXQRFO9JK: 
PUBLIC.NOMINATION FOREIGN KEY(COMPETITION_ID) 
REFERENCES PUBLIC.COMPETITION(ID) (CAST(2 AS BIGINT))"; SQL statement:

insert into Nomination (id, competition_id, name) values (default, ?, ?) [23506-212]

2. Difference with find() Method

The find() method works just opposite to getReference() method and when we fetch an entity the associated SQL select query is executed at the same time. In other words, the find() method returns a fully initialized entity.

To understand the difference, we are using the previous example and replacing the getReference() call with find().

Competition competitionRef = em.find(Competition.class, 1L);

Nomination nomination = new Nomination();
nomination.setName("Test");
nomination.setCompetition(competitionRef);

em.persist(nomination);

Notice that the SELECT query has also been executed.

Hibernate: select c1_0.id,c1_0.title from Competition c1_0 where c1_0.id=?
Hibernate: insert into Nomination (id, competition_id, name) values (default, ?, ?)

Also the find() API returns null when the primary key does not exist in the database. It does not throw any exception.

3. Conclusion

In this Jakarta persistence tutorial, we learned to use the EntityManager‘s getReference() and find() APIs and their differences. We also learned about their behavior when the primary identifies does not exist in the database.

Happy Learning !!

Sourcecode on Github

Leave a Reply

3 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial