【问题标题】:How to merge child entity in Spring Data JPA如何在 Spring Data JPA 中合并子实体
【发布时间】:2020-08-19 17:57:02
【问题描述】:

我正在使用带有 CrudRepository 的 Spring Data。我正在尝试将具有 Cascade 的父级保存给子级,并且我正在为 Hibernate 提供合并子级实体的可能性,但我收到错误 a different object with the same identifier value was already associated with the session。这可能发生在他坚持两个具有其他子实体的父实体 (RecipeIngredients) 时。我试图覆盖 equals 和 hashcode 以仅关注 idname,但它没有任何改变。 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;

}

儿童在桌子中间

@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());
}

}

儿童

@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;

}

【问题讨论】:

    标签: hibernate jpa spring-data-jpa hibernate-mapping


    【解决方案1】:

    我可以给你一个我的项目的例子,我希望它会有所帮助:

    父母:

    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 + '\'' +
                    '}';
        }
    }
    
    

    孩子:

    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); // tasks is just list of the childs @see the setTasks() at the account(parent) entity

    【讨论】:

    • 好的,我知道是什么情况,您的解决方案有效,感谢您的回复,但由于持久性,它有效,您首先从基础中检索对象,然后将其从列表中删除。我想在子对象持久化之前合并它们。我认为 hibernate 会为我做这件事,但我们可以看到它不是。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 2018-09-18
    • 2019-04-17
    • 1970-01-01
    • 2018-12-03
    • 2015-09-11
    相关资源
    最近更新 更多