如何在Spring Data JPA中合并子实体

问题描述 投票:1回答:1

我正在将Spring Data与CrudRepository一起使用。我正在尝试将“级联父项”保存到子项中,并且给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个回答
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

© www.soinside.com 2019 - 2024. All rights reserved.