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

Can I use only Entity's id instead of fetching an entity from DB when there is a relationship in an Entity?

我正在使用 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。这只是一个说明这个想法的简单示例,它是旧遗留项目的一部分,我无法修改它以从数据库中删除常量,而是使用枚举。

为避免额外调用数据库,您应该使用:

FoodType foodType = foodTypeRepository.getOne(FoodType.PERISHABLE); 

在后台它调用 EntityManager.getReference 获取对实体的引用而无需加载其数据foodTypeRepository.findById 则导致调用 EntityManager.find 获取实体及其数据

另请参阅休眠文档的 this section

P.S。您不能使用:

Food food = new Food();
FoodType foodType = new FoodType();
foodType.setFoodTypeId(FoodType.PERISHABLE);

在这种情况下,hibernate 将 foodType 视为 transient 实体(不与 @ManyToOne 关联上的 persistence context) and will try to save it as a new record if you have a proper cascading 关联。

P.S.S.正如 documentation 中提到的那样,方法 JpaRepository#getOne(ID) 已被弃用,您应该改用 JpaRepository#getById(ID)

您不需要获取与 FoodType.PERISHABLE 关联的实体来设置 Food 实体与它的关系,我不知道使用它有任何副作用或陷阱FoodType.PERISHABLE 只要是有效的 FoodType id 就直接。

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

T getById(ID id) Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is implemented this is very likely to always return an instance and throw an EntityNotFoundException on first access. Some of them will reject invalid identifiers immediately.