英文:
Why do I have to sync a bidirectional relationship even with CascadeType.PERSIST using Spring Data JPA
问题
以下是演示问题的示例代码:
餐饮实体:
@Entity
public class Meal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToMany(mappedBy = "meal", cascade = CascadeType.PERSIST)
private Collection<Food> foods;
public Meal() {
foods = new HashSet<>();
}
public Collection<Food> getFoods() {
return foods;
}
public void addFood(Food food) {
foods.add(food);
// without this the `meal_id` column is null
food.setMeal(this);
}
}
食物实体:
@Entity
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne
private Meal meal;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Meal getMeal() {
return meal;
}
public void setMeal(Meal meal) {
this.meal = meal;
}
}
以下是创建并保存实体的代码:
Meal meal = new Meal();
for (int i = 0; i < 10; i++) {
meal.addFood(new Food());
}
mealRepository.save(meal);
由于存在 CascadeType.PERSIST
,餐饮和食物实体都会持久化,但如果不显式设置食物实体的 meal
字段为对应的餐饮实体,meal_id
列会保持为空。这不是我预期的行为,我想知道为什么不能自动执行这个操作。
英文:
Here is an example code demonstrating the issue:
The Meal Entity:
@Entity
public class Meal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToMany(mappedBy = "meal", cascade = CascadeType.PERSIST)
private Collection<Food> foods;
public Meal() {
foods = new HashSet<>();
}
public Collection<Food> getFoods() {
return foods;
}
public void addFood(Food food) {
foods.add(food);
// without this the `meal_id` column is null
food.setMeal(this);
}
}
The Food Entity:
@Entity
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne
private Meal meal;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Meal getMeal() {
return meal;
}
public void setMeal(Meal meal) {
this.meal = meal;
}
}
And here is the code that creates and saves the entities:
Meal meal = new Meal();
for (int i = 0; i < 10; i++) {
meal.addFood(new Food());
}
mealRepository.save(meal);
Both the Meal and the Food entities are persisted thanks to the CascadeType.PERSIST
, but the meal_id
column stays null if I don't explicitly set the meal
field to the Meal entity.
This is not the behavior I'd expect, and I'm wondering why isn't this automatically done for me.
答案1
得分: 4
@Entity
public class Meal {
@OneToMany(mappedBy = "meal", cascade = CascadeType.PERSIST)
private Collection<Food> foods;
}
这里的mappedBy
意味着Food
类中的meal
字段的值被用来提供连接Food
和Meal
之间相应数据库列(即Food
表中的meal_id
列)的值。因此,如果你不设置它,它将始终保持为空。
另一方面,没有mappedBy
意味着Meal
中的foods
字段的值被用来提供meal_id
列的值。手动同步它们的原因只是为了拥有一致的面向对象编程模型。
CascadeType.PERSIST
与设置实体的值无关。它不会自动更新实体的值。它帮助的是自动在相关实体上调用一些entityManager
方法。如果没有它,你需要调用以下代码来保存所有的Food
和Meal
:
entityManager.persist(meal);
entityManager.persist(food1);
entityManager.persist(food2);
......
entityManager.persist(foodN);
有了它,你只需要调用:
entityManager.persist(meal);
剩下的entityManager.persist(foodN)
将会被“级联”自动调用。
因此,在Spring Data JPA中,不是调用:
mealRepository.save(meal);
foodRepository.persist(food1);
foodRepository.persist(food2);
......
foodRepository.persist(foodN);
而是只需要调用:
mealRepository.save(meal);
英文:
@Entity
public class Meal {
@OneToMany(mappedBy = "meal", cascade = CascadeType.PERSIST)
private Collection<Food> foods;
}
The mappedBy
here means that the value of meal
field in Food
is used to provide the value for the corresponding database column that link between Food
and Meal
(i.e. meal_id
column in Food
table). So if you do not set it, it will always remain NULL.
On the other hand, without mappedBy
means that the value of the foods
field in Meal
is used to provide the value for meal_id
column. The reason of manually syncing them is just to have a consistent OOP model to work with.
CascadeType.PERSIST
is nothing to do with setting the value of the entity. It will never update the value of the entities for you. What it helps is to automatically calling some entityManager
methods on the related entities. Without it, you have to call the following to save all Food and Meal:
entityManager.persist(meal);
entityManager.persist(food1);
entityManager.persist(food2);
......
entityManager.persist(foodN);
With it , you just need to call
entityManager.persist(meal);
and the rest of entityManager.persist(foodN)
will be 'cascaded' to call automatically.
So in term of spring-data-jpa , instead of calling
mealRepository.save(meal);
foodRepository.persist(food1);
foodRepository.persist(food2);
......
foodRepository.persist(foodN);
You just need to call
mealRepository.save(meal);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论