I have the following code for many to many relationship persistence using Spring JPA. This seems to work the first time, but on subsequent saves it fails.
@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>();
}
and rel class ( a new class is added here because I need additional columns on this table
@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;
}
and category class
@Entity
public class ProductAttribute {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@NotNull
private String name;
}
and code to save
@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";
}
The first time save is called seems to work fine and updates the tables as expected. However the second time save is called with additional items to save, when I try to additional rows for rel table, seems to be failing with error
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'product_category_id' cannot be null
What am I doing wrong here
ProductCategoryToProductAttributeRelrecord association fromProductCategoryusing the iterator.ProductCategoryToProductAttributeRel.productCategoryand it can't due to being part of primary key.ProductCategory.If you are using JPA 2.0 try using
orphanRemoval=true)The below could be another error which I noticed
Place your
it.next()outside the for loop as I don't think you intended it to increment multiple times per single while iteration.i.e. replace your while block with something like below.
That could be the reason it works the first time (as the while loop could be empty the first time).