首页 > 解决方案 > “分离的实体传递给坚持”当我尝试坚持具有多对多关系的实体时

问题描述

我知道有很多类似的问题,但是我没有遇到一个可以解决我的问题的问题,而且我已经尝试了所有可能的方法-我阅读了。

所以问题基本上是我无法在我的代码中保留一个实体“Recipe”的实例,该实体“Recipe”与我的h2数据库中的另一个“Category”有ManyToMany关系,而之前没有在代码流中保留类别实例。

这个“配方”实体已经在其声明中包含许多其他实体(Notes - OneToOne,成分 OneToMany),并且一切都可以完美地工作,而无需之前保留它们。

categoryRepository.save(newCategory);
recipeRepository.save(perfectGuacamole);

所以,这段代码完美地工作,但我想避免在类别之前坚持,就像我已经为其他实体所做的那样。因此,基本上即使不保存其余实体(成分、注释),此代码也会隐式地保留它们。

代码:

    Category american = categoryRepository.findByDescription("American").get();
    Category mexican = categoryRepository.findByDescription("Mexican").get();


    Recipe perfectGuacamole = new Recipe();
    Set<Recipe> newCategoryRecipes = new HashSet<>();
    newCategoryRecipes.add(perfectGuacamole);

    // CREATING A NEW CATEGORY
    Category newCategory = new Category();
    newCategory.setDescription("New");
    newCategory.setRecipes(newCategoryRecipes);

    // CRIATING A NEW SET OF GUACAMOLE'S CATEGORIES
    Set<Category> categories = new HashSet<>();
    categories.add(newCategory);
    categories.add(american);
    categories.add(mexican);


    // CREATING GUACAMOLE'S NOTES
    Notes notes = new Notes();
    notes.setRecipe(perfectGuacamole);
    notes.setRecipeNotes("Be careful handling chiles if using. Wash your hands thoroughly after handling and do not touch your eyes or the area near your eyes with your hands for several hours.");

    // CRIATING GUACAMOLE'S INGREDIENT'S
    Set<Ingredient> ingredientesGuacamole = new HashSet<>();
    Ingredient avocado = new Ingredient("Avocado", new BigDecimal(2), unitOfMeasureRepository.findByDescription("Unit").get(), perfectGuacamole);
    Ingredient salt = new Ingredient("Salt", new BigDecimal(0.25), unitOfMeasureRepository.findByDescription("Teaspoon").get(), perfectGuacamole);
    Ingredient lemonJuice = new Ingredient("Lemon juice", new BigDecimal(0.25), unitOfMeasureRepository.findByDescription("Tablespoon").get(), perfectGuacamole);

    ingredientesGuacamole.add(avocado);
    ingredientesGuacamole.add(salt);
    ingredientesGuacamole.add(lemonJuice);
    perfectGuacamole.setCookTime(10);
    perfectGuacamole.setDifficulty(Difficulty.MODERATE);
    perfectGuacamole.setDescription("The best guacamole keeps it simple: just ripe avocados, salt, a squeeze of lime, onions, chiles, cilantro, and some chopped tomato. Serve it as a dip at your next party or spoon it on top of tacos for an easy dinner upgrade.");
    perfectGuacamole.setCategories(categories);
    perfectGuacamole.setUrl("https://www.simplyrecipes.com/recipes/perfect_guacamole/");
    perfectGuacamole.setDirections("1 Cut the avocado, remove flesh: Cut the avocados in half. Remove the pit. Score the inside of the avocado with a blunt knife and scoop out the flesh with a spoon. (See How to Cut and Peel an Avocado.) Place in a bowl.\n" +
            "2 Mash with a fork: Using a fork, roughly mash the avocado. (Don't overdo it! The guacamole should be a little chunky.)\n" +
            "3 Add salt, lime juice, and the rest: Sprinkle with salt and lime (or lemon) juice. The acid in the lime juice will provide some balance to the richness of the avocado and will help delay the avocados from turning brown.\n" +
            "Add the chopped onion, cilantro, black pepper, and chiles. Chili peppers vary individually in their hotness. So, start with a half of one chili pepper and add to the guacamole to your desired degree of hotness.\n" +
            "Remember that much of this is done to taste because of the variability in the fresh ingredients. Start with this recipe and adjust to your taste.\n" +
            "Chilling tomatoes hurts their flavor, so if you want to add chopped tomato to your guacamole, add it just before serving.\n" +
            "4 Serve: Serve immediately, or if making a few hours ahead, place plastic wrap on the surface of the guacamole and press down to cover it and to prevent air reaching it. (The oxygen in the air causes oxidation which will turn the guacamole brown.) Refrigerate until ready to serve.");
    perfectGuacamole.setIngredients(ingredientesGuacamole);
    perfectGuacamole.setNotes(notes);
    perfectGuacamole.setServings(4);

    categoryRepository.save(newCategory);
    recipeRepository.save(perfectGuacamole);

配方实体:

@Entity
public class Recipe {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String description;
private Integer prepTime;
private Integer cookTime;
private Integer servings;
private String source;
private String url;

@Lob
private String directions;

@Lob
private Byte[] image;

@Enumerated(value = EnumType.STRING)
private Difficulty difficulty;

@OneToOne(cascade = CascadeType.ALL)
private Notes notes;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe")
private Set<Ingredient> ingredients;


@ManyToMany
@JoinTable(name = "recipe_category",
        joinColumns = @JoinColumn(name = "recipe_id"),
        inverseJoinColumns = @JoinColumn(name = "category_id")
)
private Set<Category> categories = new HashSet<>();


public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

public Integer getPrepTime() {
    return prepTime;
}

public void setPrepTime(Integer prepTime) {
    this.prepTime = prepTime;
}

public Integer getCookTime() {
    return cookTime;
}

public void setCookTime(Integer cookTime) {
    this.cookTime = cookTime;
}

public Integer getServings() {
    return servings;
}

public void setServings(Integer servings) {
    this.servings = servings;
}

public String getSource() {
    return source;
}

public void setSource(String source) {
    this.source = source;
}

public String getUrl() {
    return url;
}

public void setUrl(String url) {
    this.url = url;
}

public String getDirections() {
    return directions;
}

public void setDirections(String directions) {
    this.directions = directions;
}

public Byte[] getImage() {
    return image;
}

public void setImage(Byte[] image) {
    this.image = image;
}

public Difficulty getDifficulty() {
    return difficulty;
}

public void setDifficulty(Difficulty difficulty) {
    this.difficulty = difficulty;
}

public Notes getNotes() {
    return notes;
}

public void setNotes(Notes notes) {
    this.notes = notes;
}

public Set<Ingredient> getIngredients() {
    return ingredients;
}

public void setIngredients(Set<Ingredient> ingredients) {
    this.ingredients = ingredients;
}


public Set<Category> getCategories() {
    return categories;
}

public void setCategories(Set<Category> categories) {
    this.categories = categories;
}

}

类别实体:

@Entity
public class Category {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;


@ManyToMany(mappedBy = "categories")
private Set<Recipe> recipes = new HashSet<>();

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}


public Set<Recipe> getRecipes() {
    return recipes;
}

public void setRecipes(Set<Recipe> recipes) {
    this.recipes = recipes;
}
}

观察:我已经知道要工作,我应该使用 Cascate 注释,关键是即使使用它,它也不起作用。

我已经尝试在关系的每一方都使用 Fetch.eager,但它也不起作用,甚至将属性 spring.jpa.open-in-view 设置为 false。

也许我应该实现一个自定义存储库层,里面有一个实体管理器来“手动”处理它。但我不知道我应该如何进行。

我希望你们能找到解决办法。提前致谢。

编辑:分离的实体是类别。

标签: javahibernatejpa

解决方案


您可以将级联属性添加到@ManyToMany配方模型中的注释并重试吗?代码将如下所示:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "recipe_category",
        joinColumns = @JoinColumn(name = "recipe_id"),
        inverseJoinColumns = @JoinColumn(name = "category_id")
)
private Set<Category> categories = new HashSet<>();

推荐阅读