JPA级联持久化错误

6
我有一个一对多的关系:一个产品类别可以包含多个产品。这是代码:

@Entity
public class Product implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private String id;
    @Column(name="ProductName")
    private String name;
    private BigDecimal price;
    private String description;
    @ManyToOne 
    @JoinColumn(name="UserId")
    private User user;
    @ManyToOne
    @JoinColumn(name="Category")
    private ProductCategory category;
    private static final long serialVersionUID = 1L;

    public Product() {
        super();
    }   
    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }   
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }   
    public BigDecimal getPrice() {
        return this.price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }   
    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }   
    public User getUser() {
        return this.user;
    }

    public void setUser(User user) {
        this.user = user;
    }   
    public ProductCategory getCategory() {
        return this.category;
    }

    public void setCategory(ProductCategory category) {
        this.category = category;
    }
}


@Entity
public class ProductCategory {
    @Id
    private String categoryName;
    @OneToMany(cascade= CascadeType.ALL,mappedBy="category")
    private List<Product> products;

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String productName) {
        this.categoryName = productName;
    }

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }

}

这是使用两个实体的Servlet代码:
String name = request.getParameter("name");
BigDecimal price = new BigDecimal(request.getParameter("price"));
String description = request.getParameter("description");
ProductCategory category = new ProductCategory();
category.setCategoryName(request.getParameter("category"));
Product product = new Product();
product.setName(name);
product.setPrice(price);
product.setDescription(description);
product.setCategory(category);
User user = userManager.findUser("Meow");
product.setUser(user);
productManager.createProduct(product);  // productManager is an EJB injected by container

以下是错误信息:

java.lang.IllegalStateException: 在同步期间,发现了一个未标记为级联PERSIST的关系中的新对象

为什么会出现这个错误?我已经将字段标记为“cascade = CascadeType.All”了!

1个回答

10
你试图保存一个产品,该产品与某个类别相关联。因此,当JPA保存产品时,它的类别必须已经存在,或者必须配置级联操作,以便将产品持久化级联到持久化其类别。
但你没有这样的级联。你有的是一个级联,它表示对类别执行的任何操作都会级联到其产品列表。

那我该怎么办呢?如果我把代码改成:@OneToMany(cascade= CascadeType.PERSIST,mappedBy="category") private List<Product> products; 也不行。它会给出相同的错误。 - user477768
4
级联关系的方向不正确。您告诉 JPA:“当我要求您持久化一个类别时,请也持久化其产品”。但您没有要求 JPA 持久化类别,而是要求它持久化产品。而且在任何地方都没有说明当持久化一个产品时,必须持久化其所属的类别。 - JB Nizet
你认为级联符号应该放在哪一边呢?据我所知,在多对一(Many-To-One)关系中,它总是出现在反向端(即"one-side"或者另一种说法,就是包含@OneToMany注释的那一侧)。 - user477768
3
一个协会只有两个方面,而你的级联在你想要做的那一边是错误的。你得出什么结论?你的假设是错误的。你可以把级联放在任何一边。 - JB Nizet
当实体在数据库中已经存在但不再受管理时,我经常会遇到这个错误。我必须获取对它的引用。这非常令人烦恼。 - Ced

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接