我将 Spring Data 与 CrudRepository
结合使用.我正在尝试将 Parent with Cascade 保存到子实体,并且我正在为 Hibernate 提供合并子实体的可能性,但我收到错误 a different object with the same identifier value was already associated with the session
.当他坚持两个具有其他子实体(RecipeIngredients
)的父实体时,可能会发生这种情况。我正在尝试覆盖 equals 和 hashcode 以仅关注 id
和 name
,但它没有任何改变。 Recipe
对象相同但 List<RecipeIgredients>
是不同的。关于如何解决它的任何想法?
例子:
这是我存在的对象:
{
"id": 100,
"name": "salat",
"ingredients": [
{
"ingredient": {
"id": 100,
"name": "banana"
},
"count": 2
},
{
"ingredient": {
"id": 1,
"name": "eggs"
},
"count": 1
}
]
}
我想将其更新为以下(删除一种成分):
{
"id": 100,
"name": "salat",
"ingredients": [
{
"ingredient": {
"id": 100,
"name": "bannana"
},
"count": 2
}
]
}
父级:
@Entity
@Data
public class Recipe {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "recipe_generator")
@SequenceGenerator(name="recipe_generator", sequenceName = "recipe_seq")
@Column(name = "id", nullable = false)
private Long id;
@NaturalId
@Column
private String name;
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true)
private List<RecipeIngredients> ingredients;
}
child 在中 table
@Entity
@Data
public class RecipeIngredients implements Serializable {
@EmbeddedId
private RecipeIngredientsId recipeIngredientsId;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("recipeId")
private Recipe recipe;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@MapsId("ingredientId")
private Ingredient ingredient;
@Column
private Integer count;
public RecipeIngredients(Recipe recipe, Ingredient ingredient) {
this.recipe = recipe;
this.ingredient = ingredient;
this.recipeIngredientsId = new RecipeIngredientsId(recipe.getId(), ingredient.getId());
}
child
@Entity
@Data
public class Ingredient {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ingredient_generator")
@SequenceGenerator(name="ingredient_generator", sequenceName = "ingredient_seq")
@Column(name = "id", updatable = false, nullable = true)
private Long id;
@NaturalId
@Column(unique = true)
private String name;
}
最佳答案
我可以举一个我的项目的例子,希望它能有所帮助:
父级:
package com.yoav.todolist.models;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "accounts")
public class Account {
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@OneToMany(
mappedBy = "account",
orphanRemoval = true,
cascade = CascadeType.ALL
)
private List<Task> tasks = new ArrayList<>();
public Account(String username, String password) {
this.username = username;
this.password = password;
}
public Account() {
}
public void removeTask(Task task) {
tasks.remove(task);
task.setAccount(null);
}
public void addTask(Task task) {
tasks.add(task);
task.setAccount(this);
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks.forEach(i -> i.setAccount(null));
this.tasks.clear();
tasks.forEach(i -> {
i.setAccount(this);
addTask(i);
});
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public boolean equals(Object account) {
return ((Account)account).getUsername().equals(this.username);
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
child :
package com.yoav.todolist.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "tasks")
public class Task {
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "task")
private String task;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private Account account;
@Temporal(TemporalType.DATE)
@Column(name = "date_of_creation_task")
private Date date;
public Task(String task) {
this.date = new Date();
this.task = task;
}
public Task() {
this.date = new Date();
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTask() {
return task;
}
public void setTask(String task) {
this.task = task;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public boolean equals(Object task) {
return ((Task)task).getId() == this.id;
}
@Override
public String toString() {
return "Task{" +
"id=" + id +
", task='" + task + '\'' +
'}';
}
@Override
public int hashCode() {
return 31;
}
}
在我的例子中,我只需要获取实体,例如 accountSerice.getById(1);
然后在我的例子中,我只需要执行 account.setTasks(tasks);//任务只是 child 的列表@see 帐户(父)实体中的 setTasks()
关于hibernate - 如何在 Spring Data JPA 中合并子实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61606944/