我想为食谱分配一个类别。如果我给配方分配了另一个具有相同名称的类别,它将对数据库进行另一个插入,该数据库将中止(由于违反约束而异常终止(唯一约束失败:category.name)-这实际上很好)。我想重复使用此条目并将其附加到配方。是否有JPA方法“自动”执行此操作,还是我必须处理此问题?我是否应该在setCategory方法中搜索具有相同名称的类别,并在存在时使用该类别?有模式吗?
@Entity
public class Recipe {
private Integer id;
private Category category;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "category_id", referencedColumnName = "id")
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
@Entity
public class Category {
private Integer id;
private String name;
private List<Recipe> recipes;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Basic
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy = "category", cascade = {CascadeType.ALL})
public List<Recipe> getRecipes() {
return recipes;
}
public void setRecipes(List<Recipe> recipes) {
this.recipes = recipes;
}
}
例:
Category category = new Category();
category.setName("Test Category");
cookbookDAO.add(cookbook);
Recipe recipe = new Recipe();
recipe.setTitle("Test Recipe");
recipe.setCategory( category );
recipeDAO.add(recipe);
两次执行此操作将导致UNIQUE约束失败:category.name。这很好,因为我不想使用相同名称的多个类别。数据库强制执行此操作,但我也在寻找在Java语言级别强制执行此操作的方法。
DDL:
CREATE TABLE "recipe"
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
category_id INTEGER,
FOREIGN KEY (category_id) REFERENCES category(id)
);
CREATE TABLE "category"
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
`name` VARCHAR,
UNIQUE(`name`) ON CONFLICT ABORT
);
最佳答案
您好,您描述的行为是映射的结果
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "category_id", referencedColumnName = "id")
public Category getCategory() {
return category;
}
如果我们翻译这种映射是简单的语言。你是说:
每当我尝试保存食谱时,相应的类别应
也要坚持下去。
这里的问题是由于您已经具有一个现有的类别,因此这里的@ Cascade.PERSIST不适用。
这里的语义是相反的。仅当类别尚不存在时,食谱才创建类别。这意味着类别的创建比一般规则更多的是例外。
这意味着您在这里有两个选择。
选项1是删除Cascade.PERSIST。
选项2是用Cascade.MERGE替换它。
选项3是另一种方式。而不是使用Cascade.PERSIST在“食谱到类别”中注释@ManyToOne关系,以在“类别”到食谱中注释@OneToMany关系。
这种方法的优点非常简单。虽然您在添加新配方时并不总是希望创建新类别。您要一直添加新类别的时间是100%,您还想添加所有附加的收件人。
另外,我还建议您偏爱双向关系而不是单向关系,并阅读有关合并和持久化JPA EntityManager: Why use persist() over merge()?的文章。