When to use EntityManager.find() vs EntityManager.getReference() with JPA
I usually use getReference method when i do not need to access database state (I mean getter method). Just to change state (I mean setter method). As you should know, getReference returns a proxy object which uses a powerful feature called automatic dirty checking. Suppose the following
public class Person {
private String name;
private Integer age;
}
public class PersonServiceImpl implements PersonService {
public void changeAge(Integer personId, Integer newAge) {
Person person = em.getReference(Person.class, personId);
// person is a proxy
person.setAge(newAge);
}
}
If i call find method, JPA provider, behind the scenes, will call
SELECT NAME, AGE FROM PERSON WHERE PERSON_ID = ?
UPDATE PERSON SET AGE = ? WHERE PERSON_ID = ?
If i call getReference method, JPA provider, behind the scenes, will call
UPDATE PERSON SET AGE = ? WHERE PERSON_ID = ?
And you know why ???
When you call getReference, you will get a proxy object. Something like this one (JPA provider takes care of implementing this proxy)
public class PersonProxy {
// JPA provider sets up this field when you call getReference
private Integer personId;
private String query = "UPDATE PERSON SET ";
private boolean stateChanged = false;
public void setAge(Integer newAge) {
stateChanged = true;
query += query + "AGE = " + newAge;
}
}
So before transaction commit, JPA provider will see stateChanged flag in order to update OR NOT person entity. If no rows is updated after update statement, JPA provider will throw EntityNotFoundException according to JPA specification.
regards,
What is the difference between EntityManager.find() and EntityManger.getReference()?
JPA has the concept of an EntityManager, as you know. During your work in the entity manager some objects are loaded from the database, can be modified and afterwards flushed to the database.
find()
has to return an initialized instance of your object. If it is not already loaded in the EntityManager, it is retrieved from the database.
getReference()
is allowed to return a proxy instead of an initialized instance, if the entity has not been loaded in the EntityManager before. In this proxy, only the primary key attribute is initialized. Proxies can be created without hitting the database, because the only initialized attribute is already given to the getReference() function.
The latter is useful when you have an entity A referencing an entity B, and you want to set the b-attribute of A to B, without having to load B from the database.
Only if you reference other attributes of B, the proxy will be initialized.
Difference between CrudRepository findOne() and JpaRepository getOne()
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
How do I use JPA's entityManager.getReference in Spring Boot?
It's injected normally, Spring Boot has nothing to do with it (Spring Boot is just Spring albeit with some configuration differences).
Just add
@PersistenceContext
private EntityManager em;
to your class and you can access the raw EntityManager
object and all that it offers. There's nothing wrong with using it, you can't get everything done with repositories.
difference between getReference() and load()
EntityManager#getReference()
is functionally equal tosession#load()
. This can be verified by the hibernate 's EntityManager implementation (AbstractEntityManagerImpl
) which delegates the work to session#load().session#load()
andsession#get()
have some difference in behaviour . For details , please see this.IdentifierLoadAccess
is under the packageorg.hibernate
. So it is Hibernate native API . All interfaces defined by JPA specification are under the packagejavax.persistence
.JPA are standard Java API for persistence which means if your application only uses JPA API , theoretically , it is portable between different JPA providers. You application would work even you change to use other JPA provider only switch to other JavaEE application server.
Spring Jpa Entity - EntityManager.getReference
First, you should add @ManyToOne relation to the pet
property:
@Entity
@Table(name = "PERSON")
public class Person {
//...
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "pet_guid")
privat Pet pet;
}
It says to Hibernate to use a foreign key to the Pet
entity (and its table).
Second, you should use the method getOne
of your PersonRepository
to get a reference to the Pet
entity, for example:
@Service
public class PersonService {
private final PetRepository petRepo;
private final PersonRepository personRepo;
//...
@NonNull
@Transactional
public Person create(@NonNull final PersonDto personDto) {
Person person = new Person();
//...
UUID petId = personDto.getPetId();
Pet pet = petRepo.getOne(perId);
person.setPet(pet);
//...
return person.save(person);
}
}
Related Topics
Difference in System. Exit(0) , System.Exit(-1), System.Exit(1 ) in Java
Filter Jacoco Coverage Reports with Gradle
Convert a String (Like Testing123) to Binary in Java
Instanceof - Incompatible Conditional Operand Types
How to Avoid Constructor Code Redundancy in Java
How to Configure Encoding in Maven
Leiningen - How to Add Dependencies for Local Jars
Communication Between Two Separate Java Desktop Applications
Remove() on List Created by Arrays.Aslist() Throws Unsupportedoperationexception
Spring Boot Rest API - Request Timeout
How to Format a Java String with Leading Zero
Return Generated PDF Using Spring MVC
What Is the Breakdown for Java's Lambda Syntax
How Is Countdownlatch Used in Java Multithreading