我想为食谱分配一个类别。如果我给配方分配了另一个具有相同名称的类别,它将对数据库进行另一个插入,该数据库将中止(由于违反约束而异常终止(唯一约束失败: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()?的文章。

10-07 19:15