当实体中存在关系时,是否可以仅使用实体的 ID 而不是从数据库中获取实体?



我将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的任何副作用或陷阱,只要它是有效的FoodTypeid即可。

正如其他人提到的,您也可以使用JpaRepository#getById(ID ID(,这可能是解决这个问题的更规范的方法:

T getById(ID ID(返回对给定标识符。取决于JPA持久性提供程序的方式实现了这个很可能总是返回一个实例并抛出第一次访问时出现EntityNotFoundException。他们中的一些人会拒绝立即使用无效标识符。

最新更新