I have two entities
@Entity
@Table(name = "categories")
public class Category {
@Getter
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id", unique = true, nullable = false)
private long categoryId;
@Getter @Setter
@ManyToMany(mappedBy = "categories", cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
List<Product> products;
@Getter @Setter
@Column(name = "category_name", nullable = false, unique = true)
private String categoryName;
And
@Entity
@Table(name = "products")
public class Product {
@Getter
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "product_id", unique = true, nullable = false)
private long productId;
@Getter @Setter
@Column(name = "price")
private float price;
@Getter @Setter
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "categories_product")
private List<Category> categories;
@Getter @Setter
@Column(name = "product_code", unique = true, nullable = false)
private String productCode;
@Getter @Setter
@Column(name = "product_name", nullable = false)
private String productName;
@Getter @Setter
@Column(name = "description", nullable = false)
private String description;
@Getter @Setter
@Column(name = "short_description", nullable = false)
private String shortDescription;
}
I`m using MapStruct for DTO. When I want to add new product through controller I get the following error:
org.hibernate.PropertyValueException: not-null property references a null or transient value : com.project.shop.models.Category.categoryName
As I understand, hibernate tries to create a new Category, when I want it to use an already existing one in database.
CategoryDTO:
@Getter
@Setter
public class CategoryDto {
private long categoryId;
private String categoryName;
private boolean categoryActive;
}
ProductDTO:
@Getter
@Setter
public class ProductDto {
private String productName;
private String productCode;
private float price;
private String shortDescription;
private String description;
private List<CategoryDto> categories;
}
CategoryMapper:
@Mapper(componentModel = "spring")
public interface CategoryMapper {
CategoryDto toDto(Category category);
List<CategoryDto> toDtos(List<Category> categories);
List<Category> toModels(List<CategoryDto> categoryDtos);
Category toModel(CategoryDto categoryDto);
}
ProductMapper:
@Mapper(uses = {CategoryMapper.class},
componentModel = "spring")
public interface ProductMapper {
ProductDto toDto(Product product);
List<ProductDto> toDtos(List<Product> products);
List<Product> toModels(List<ProductDto> productDtos);
Product toModel(ProductDto productDto);
}
Controller:
@PostMapping("/product")
public ResponseEntity<ProductDto> create(@RequestBody ProductDto productDto) {
productService.save(productMapper.toModel(productDto));
return ResponseEntity.status(HttpStatus.CREATED).body(productDto);
}
productService.save:
public void save(Product product) {
productRepository.save(product);
}
If you look at the identity, nullable = false option appears to be defined option is defined.
@Entity
@Table(name = "categories")
public class Category {
....
@Getter @Setter
@Column(name = "category_name", nullable = false, unique = true)
private String categoryName;
I think it would be good to look for the categoryName column value of CategoryDto first.