8

I read that getOne() is lazy loaded and findOne() fetches the whole entity right away. I've checked the debugging log and I even enabled monitoring on my sql server to see what statements gets executed, I found that both getOne() and findOne() generates and executes the same query. However when I use getOne() the values are initially null (except for the id of course).

So could anyone please tell me, if both methods executes the same query on the database, why should I use one over the other? I'm basically looking for a way to fetch an entity without getting all of its children/attributes.

EDIT1:

Entity code

Dao code:

@Repository
public interface FlightDao extends JpaRepository<Flight, Long> {
}

Debugging log findOne() vs getOne()

EDIT2:

Thanks to Chlebik I was able to identify the problem. Like Chlebik stated, if you try to access any property of the entity fetched by getOne() the full query will be executed. In my case, I was checking the behavior while debugging, moving one line at a time, I totally forgot that while debugging the IDE tries to access object properties for debugging purposes (or at least that's what I think is happening), so debugging triggers the full query execution. I stopped debugging and then checked the logs and everything appears to be normal.

getOne() vs findOne() (This log is taken from MySQL general_log and not hibernate.

Debugging log

No debugging log

Vladimir Vagaytsev
  • 2,650
  • 9
  • 31
  • 30
prettyvoid
  • 2,854
  • 4
  • 29
  • 47

3 Answers3

10

It is just a guess but in 'pure JPA' there is a method of EntityManager called getReference. And it is designed to retrieve entity with only ID in it. Its use was mostly for indicating reference existed without the need to retrieve whole entity. Maybe the code will tell more:

// em is EntityManager
Department dept = em.getReference(Department.class, 30);  // Gets only     entity with ID property, rest is null
Employee emp = new Employee();
emp.setId(53);
emp.setName("Peter");
emp.setDepartment(dept);
dept.getEmployees().add(emp);
em.persist(emp);

I assume then getOne serves the same purpose. Why the queries generated are the same you ask? Well, AFAIR in JPA bible - Pro JPA2 by Mike Keith and Merrick Schincariol - almost every paragraph contains something like 'the behaviour depends on the vendor'.

EDIT:

I've set my own setup. Finally I came to conclusion that if You in any way interfere with entity fetched with getOne (even go for entity.getId()) it causes SQL to be executed. Although if You are using it only to create proxy (eg. for relationship indicator like shown in a code above), nothing happens and there is no additional SQL executed. So I assume in your service class You do something with this entity (use getter, log something) and that is why the output of these two methods looks the same.

ChlebikGitHub with example code
SO helpful question #1
SO helpful question #2

Community
  • 1
  • 1
Chlebik
  • 612
  • 1
  • 8
  • 24
  • Thanks for the information. Actually what `getOne()` does is call `getReference()`. I'm really confused because as I stated earlier both methods generated and executed the same query! So maybe it have to do with MySQL like you stated? I really wish somebody can confirm this. Do you have any idea if the query should differ between the two methods in a normal scenario? – prettyvoid Oct 19 '15 at 16:36
  • The vendor does not mean eg. MySQL but Hibernate/TopLink/whatever You use. I assume query being executed is based on defined relations in Your entities and probably optimalization done by JPA implementation. IMHO with simple entity there is not much difference between fetching handler to an entity (like with **getReference**) and actual retrieval of all the data. – Chlebik Oct 19 '15 at 16:46
  • I have to get a reference because the entities I try to fetch have a lot of sub-entities, it's a lot of work to fetch the whole thing when I only need the ID of the entity. Let's wait a while maybe someone can tell us what's happening. Thanks again – prettyvoid Oct 19 '15 at 17:05
  • Please post your entity code. There is several possibilities to think of but without code I can not say anything. – Chlebik Oct 19 '15 at 17:25
  • Check my second edit. I really can't upvote you enough.. and I feel so dumb right now :-| Thanks a lot Chlebik :) – prettyvoid Oct 20 '15 at 12:21
4

Suppose you want to remove an Entity by id. In SQL you can execute a query like this :

"delete form TABLE_NAME where id = ?". 

And in Hibernate, first you have to get a managed instance of your Entity and then pass it to EntityManager.remove method.

Entity a = em.find(Entity.class, id);
em.remove(a);

But this way, You have to fetch the Entity you want to delete from database before deletion. Is that really necessary ?

The method EntityManager.getReference returns a Hibernate proxy without querying the database and setting the properties of your entity. Unless you try to get properties of the returned proxy yourself.

Method JpaRepository.getOne uses EntityManager.getReference method instead of EntityManager.find method. so whenever you need a managed object but you don't really need to query database for that, it's better to use JpaRepostory.getOne method to eliminate the unnecessary query.

chubock
  • 664
  • 7
  • 14
0

If data is not found the table for particular ID, findOne will return null, whereas getOne will throw javax.persistence.EntityNotFoundException. Both have their own pros and cons. Please see example below:

  1. If data not found is not failure case for you (eg. You are just verifying if data the data is deleted and success will be data to be null), you can use findOne.
  2. In another case, you can use getOne.

This can be updated as per your requirements, if you know outcomes.

סטנלי גרונן
  • 2,740
  • 21
  • 43
  • 62