Issue
I am using Spring Data JPA with Hibernate.
Lets say I have the following entity defined:
@Entity
@Table(name = "foods")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "food_id")
private Long foodId;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "food_type_id")
@NotNull
private FoodType foodType;
...
}
@Entity
@Table(name = "food_types")
public class FoodType {
public static final Integer PERISHABLE;
public static final Integer NON_PERISHABLE;
@Id
@Column(name = "food_type")
private Integer foodTypeId;
private String name;
...
}
Every time when I want to create a Food
entity and save it to the database, currently code looks like this:
Food food = new Food();
FoodType foodType = foodTypeRepository.findById(FoodType.PERISHABLE); // Call to DB to get Entity
food.setFoodType(foodType);
....
foodRepository.save(food);
If we consider FoodType to be constant in the DB. Can I use it like this:
Food food = new Food();
FoodType foodType = new FoodType();
foodType.setFoodTypeId(FoodType.PERISHABLE); // No Call to DB
food.setFoodType(foodType);
....
foodRepository.save(food);
I have tested it and yes I can use it that way, hibernate will save the Food
entity, but are there any downsides, pitfalls, etc... I am not seeing.
PS. This is just a simple example illustrating the idea, it is part of old legacy project which I cannot modify to remove constant from DB, and use an enum instead.
Solution
To avoid extra call to DB you should use:
FoodType foodType = foodTypeRepository.getOne(FoodType.PERISHABLE);
under the hood it calls EntityManager.getReference
that obtain a reference to an entity without having to load its data as opposed to the foodTypeRepository.findById
that lead to call EntityManager.find
that obtain an entity along with its data.
See also this section of the hibernate documentation.
P.S. You can not use:
Food food = new Food();
FoodType foodType = new FoodType();
foodType.setFoodTypeId(FoodType.PERISHABLE);
as in this case hibernate consider foodType
as a transient entity (not associated with a persistence context) and will try to save it as a new record if you have a proper cascading on your @ManyToOne
association.
P.S.S. As it's mentioned in the documentation the method JpaRepository#getOne(ID)
is deprecated and you should use JpaRepository#getById(ID)
instead.
Answered By - SternK
Answer Checked By - Robin (JavaFixing Admin)