java - Spring JPA 多对多持久性问题

标签 java mysql spring jpa

我有以下使用 Spring JPA 进行多对多关系持久化的代码。这似乎第一次有效,但在随后的保存中却失败了。

@Entity
public class ProductCategory {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;

    @NotNull
    @Column(unique = true)
    private String name;

    @OneToMany(mappedBy = "productCategory", cascade = CascadeType.ALL)
    private Set<ProductCategoryToProductAttributeRel> productCategoryToProductAttributeRel = new HashSet<ProductCategoryToProductAttributeRel>();
}

和 rel 类(此处添加了一个新类,因为我需要在此表上添加其他列

@Entity
public class ProductCategoryToProductAttributeRel implements Serializable{
    private static final long serialVersionUID = 1L;
    private Integer id;
    @Id
    @ManyToOne
    @JoinColumn(name = "product_category_id")
    private ProductCategory productCategory;
    @Id
    @ManyToOne
    @JoinColumn(name = "product_attribute_id")
    private ProductAttribute productAttribute;
}

和类别

@Entity
public class ProductAttribute {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    @NotNull
    private String name;
}

以及要保存的代码

@RequestMapping(value = "/saveProductCategory", method = RequestMethod.POST)
public String ProductCategorySave(ProductCategoryDTO productCategoryDTO, Model model) {
    ProductCategory pc = new ProductCategory(productCategoryDTO);
    if (productCategoryDTO.getProductAttributeIds() != null
            && productCategoryDTO.getProductAttributeIds().size() > 0) {
        Iterator<ProductCategoryToProductAttributeRel> it =
                pc.getProductCategoryToProductAttributeRel().iterator();
        // removing elements
        while (it.hasNext()) {
            boolean isPresent = false;
            for (Integer paId : productCategoryDTO.getProductAttributeIds()) {
                if (it.next().getProductAttribute().getId().equals(paId)) {
                    isPresent = true; break;
                }
            }
            if (!isPresent) { it.remove(); }
        }
        for (Integer paId : productCategoryDTO.getProductAttributeIds()) {
            ProductAttribute pa = productAttributeRepository.findOne(paId);

            boolean add = true;
            for (ProductCategoryToProductAttributeRel pcToPARel :
                pc.getProductCategoryToProductAttributeRel()) {
                if (pcToPARel.getProductAttribute().getId().equals(paId)) {
                    add = false;
                }
            }
            if (add) {
                ProductCategoryToProductAttributeRel pcToPARel = new ProductCategoryToProductAttributeRel();
                pcToPARel.setProductAttribute(pa);
                pcToPARel.setProductCategory(pc);
                pc.getProductCategoryToProductAttributeRel().add(pcToPARel);
            }
        }
    }
    productCateogryRepository.save(pc);    
    return "edit-product-category";
}

第一次调用保存似乎工作正常并按预期更新表。然而,当我尝试为 rel 表添加其他行时,第二次调用保存时会使用其他要保存的项目,似乎失败并出现错误

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'product_category_id' cannot be null

我在这里做错了什么

最佳答案

  • 在我看来,该错误似乎是在 while 循环中第二次保存时引起的,在该循环中,您使用迭代器从 ProductCategory 中删除了已保存的 ProductCategoryToProductAttributeRel 记录关联。
  • 它将尝试将 null 设置为 ProductCategoryToProductAttributeRel.productCategory,但由于是主键的一部分而无法设置。
  • 要纠正此问题,您需要允许 null(即重新设计主键),或者在删除与 ProductCategory 的关联时对 Rel 实体进行删除。

如果您使用的是 JPA 2.0,请尝试使用 orphanRemoval=true)

@OneToMany(mappedBy = "productCategory", orphanRemoval=true, cascade = CascadeType.ALL)
private Set<ProductCategoryToProductAttributeRel> productCategoryToProductAttributeRel = new HashSet<ProductCategoryToProductAttributeRel>();

下面可能是我注意到的另一个错误

<小时/>

将您的 it.next() 放在 for 循环之外,因为我认为您不希望它每次 while 迭代都会增加多次。

即将 while block 替换为如下所示的内容。

// removing elements
while (it.hasNext()) {
    boolean isPresent = false;
    ProductCategoryToProductAttributeRel nextRel = it.next() // I think you wanted to increment once per while loop?
    for (Integer paId : productCategoryDTO.getProductAttributeIds()) {
        if (nextRel.getProductAttribute().getId().equals(paId)) {
            isPresent = true; break;
        }
    }
    if (!isPresent) { it.remove(); }
}

这可能是它第一次工作的原因(因为 while 循环第一次可能为空)。

关于java - Spring JPA 多对多持久性问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48733158/

相关文章:

java - 将 Spring Security 连接到 Camunda 引擎,要覆盖什么?

java - Spring Boot从请求中获取图像数据

java - JavaConfig 表示法中的 Spring freemarker 外部加载程序路径

c# - Camel 套管的缩写?

java - 如何使用Maven在界面中设置当前项目版本和项目构建时间戳?

java - 公开或什么都没有

java - InnoDB 全文搜索

php - 使用 MYSQL 数据发送电子邮件

java - 我在尝试访问 REST Web 应用程序时收到 404 错误

PHP 显示来自 MySQL 的图像 BLOB