我将Spring Data JPA与Hibernate结合使用。
假设我定义了以下实体:
@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;
...
}
每次我想创建一个Food
实体并将其保存到数据库时,当前的代码如下所示:
Food food = new Food();
FoodType foodType = foodTypeRepository.findById(FoodType.PERISHABLE); // Call to DB to get Entity
food.setFoodType(foodType);
....
foodRepository.save(food);
如果我们认为FoodType在数据库中是常量。我可以这样使用吗:
Food food = new Food();
FoodType foodType = new FoodType();
foodType.setFoodTypeId(FoodType.PERISHABLE); // No Call to DB
food.setFoodType(foodType);
....
foodRepository.save(food);
我已经测试过了,是的,我可以这样使用它,hibernate将保存Food
实体,但是否有任何缺点、陷阱等……我没有看到。
PS。这只是一个简单的例子,说明了这个想法,它是旧的遗留项目的一部分,我不能修改它来从DB中删除常量,而是使用枚举。
为了避免额外调用DB,您应该使用:
FoodType foodType = foodTypeRepository.getOne(FoodType.PERISHABLE);
在引擎盖下,它调用EntityManager.getReference
以获得对实体的引用而不必加载其数据,而foodTypeRepository.findById
导致调用EntityManager.find
来获得实体及其数据。
另请参阅hibernate文档的这一部分。
附言:你不能使用:
Food food = new Food();
FoodType foodType = new FoodType();
foodType.setFoodTypeId(FoodType.PERISHABLE);
在这种情况下,hibernate将foodType
视为瞬态实体(与持久性上下文无关(,如果在@ManyToOne
关联上有适当的级联,则会尝试将其保存为新记录。
p.S.S.正如文档中所提到的,方法JpaRepository#getOne(ID)
已被弃用,您应该使用JpaRepository#getById(ID)
。
您不需要获取与FoodType.PERISHABLE
关联的实体来设置Food
实体与它的关系,并且我不知道直接使用FoodType.PERISHABLE
的任何副作用或陷阱,只要它是有效的FoodType
id即可。
正如其他人提到的,您也可以使用JpaRepository#getById(ID ID(,这可能是解决这个问题的更规范的方法:
T getById(ID ID(返回对给定标识符。取决于JPA持久性提供程序的方式实现了这个很可能总是返回一个实例并抛出第一次访问时出现EntityNotFoundException。他们中的一些人会拒绝立即使用无效标识符。