Hibernate保存到db"重复输入' 1'对于关键' UK_2n5xttsxwbyc6x67l0x8phfwn'"

时间:2017-04-22 21:47:27

标签: java mysql spring hibernate

我有@Entity的Recipe.java对象:

...  
@OneToMany(cascade = CascadeType.ALL)
private List<Category> category;  
...  

然后使用@Entity:

的Category.java对象
...  
@OneToOne(cascade = CascadeType.ALL)  
private Name name;  
...

让我们说db看起来像这样(recipe_category表):

enter image description here

然后执行以下代码(我只想在配方中添加一个类别):

...
        Recipe recipe = recipeRepository.findOne(recipeId);
        Category ctg = categoryRepository.findOne(categoryId); // id=1

        List<Category> categories = recipe.getCategory();
        categories.add(ctg);
        recipe.setCategory(categories);

        recipeRepository.save(recipe);
...

recipeRepository.save(recipe)我收到以下错误:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'UK_2n5xttsxwbyc6x67l0x8phfwn'

那么这个问题的解决方案是什么?

更新:
 配方表结构如下所示:

enter image description here

类别表结构如下所示:

enter image description here

所以问题似乎发生了,因为当recipe.setCategory(categories);被触发时,它会尝试将ctg保存到数据库,但它已经存在。我想要的不是将它保存到db(因为&#39;类别&#39;表中已经存在),而是在recipe_category表中添加新行。

也许它必须用cascade做点什么?

2 个答案:

答案 0 :(得分:1)

你的关系不是一对多的。您希望每个食谱都有多个类别。我想你也希望每个类别与多个食谱相关联。这是一种多对多的关系。您需要使用@ManyToMany注释来配置实体。

另请注意,Hibernate关系始终是单向的。当您在@ManyToMany课程中添加Recipe注释时,您可以访问与给定食谱相关联的类别。要访问反向关系,要获取给定类别的配方,您还需要向@ManyToMany类添加带Category注释的相应属性。

我猜您使用了hbm2ddl或类似的方法来自动创建表,因为表是为一对多关系创建的,所以会出错。更具体地说,在单向一对多关系中,连接表中的逆外键列(category_id表中的recipe_category)具有在其上定义的唯一约束。因此,使用该表模式,您无法将类别与多个配方相关联。

这样的事情应该有效:

// Recipe
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="category_map", )
private List<Category> categories = new ArrayList<> ();

// Category
@ManyToMany(cascade=CascadeType.ALL, mappedBy="categories")     
private Set<Recipe> recipes;    

答案 1 :(得分:0)

Recipe recipe = recipeRepository.findOne(recipeId);
Category ctg = categoryRepository.findOne(categoryId); // id=1

List<Category> categories = recipe.getCategory();
categories.add(ctg);
recipe.setCategory(categories);

recipeRepository.save(recipe);
//categories.clear();