简体   繁体   中英

adding new entity in database through PostMapping

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);
}

It is not that easy basically. My suggestion (and my implementation) is that you pass only the categoryId with your ProductDTO . And at the service, take this ID, find the respective Category via a Repository and then set the Product's Category to this entity. Simple example:

    public ProductDTO addProduct(ProductDTO newDto) {

    Category category = categoryRepo.findById(newDto.getCategory().getId())
            .orElseThrow(// something);

    Product entity = modelMapper.map(newDto, Product.class); // This does the same thing as your mapper, You can also implement this in your project

    entity.setCategory(category );

    return modelMapper.map(productRepo.save(entity), ProductDTO.class); // This saves the entity and converts it to a DTO and returns it 
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM