【问题标题】:Duplicate field for the 'PRIMARY' key when i send data from angular to spring boot当我将数据从角度发送到弹簧启动时,“PRIMARY”键的重复字段
【发布时间】:2021-04-16 19:39:41
【问题描述】:

我在将数据从 Angular 表单发送到 Spring 启动控制器时遇到问题

请求处理失败;嵌套异常是 org.springframework.dao.DataIntegrityViolationException:无法执行语句; SQL [不适用];约束[空];嵌套异常是 org.hibernate.exception.ConstraintViolationException:无法执行语句 原因:java.sql.SQLIntegrityConstraintViolationException:“PRIMARY”键的“M”字段重复

请求处理失败;嵌套异常是 org.springframework.dao.DataIntegrityViolationException:无法执行语句; SQL [不适用];约束[空];嵌套异常是 org.hibernate.exception.ConstraintViolationException:无法执行语句 原因:java.sql.SQLIntegrityConstraintViolationException:“PRIMARY”键的“M”字段重复

上下文是这样的:我有两个类 Book 和 Category 具有 OneToMany 和 ManyToOne 关系:一个 Book 对应一个 Category( 一个 Category 对应几本书。在前面,我从当前的 4 个类别中选择一个类别在数据库中(Cuisine,Jeunesse, Informatique et Mathematique) 插入一本书时,我选择了一个类别进行连接,但不幸的是它还想插入类别,这会产生错误。如何纠正这个问题。

Entity
@Table(name = "CATEGORY")
public class Category {
    public Category() {
    }
 
    public Category(String code, String label) {
        super();
        this.code = code;
        this.label = label;
    }
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private Integer id;
 
    private String code;
 
    private String label;
    @OneToMany(mappedBy = "category", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Set<Book> book;
 
    @Column(name = "CODE")
    public String getCode() {
        return code;
    }
 
    public void setCode(String code) {
        this.code = code;
    }
 
    @Column(name = "LABEL", nullable = false)
    public String getLabel() {
        return label;
    }
 
    public void setLabel(String label) {
        this.label = label;
    }
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public Set<Book> getBook() {
        return book;
    }
 
    public void setBook(Set<Book> book) {
        this.book = book;
    }
 
}
 
 
@Entity
@Table(name = "BOOK")
public class Book {
    private Integer id;
 
    private String title;
 
    private String isbn;
 
    private LocalDate releaseDate;
 
    private LocalDate registerDate;
 
    private Integer totalExamplaries;
 
    private String author;
 
    private Category category;
 
    Set<Loan> loans = new HashSet<Loan>();
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "BOOK_ID")
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    @Column(name = "TITLE", nullable = false)
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    @Column(name = "ISBN", nullable = false, unique = true)
    public String getIsbn() {
        return isbn;
    }
 
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
 
    @Column(name = "RELEASE_DATE", nullable = false)
    public LocalDate getReleaseDate() {
        return releaseDate;
    }
 
    public void setReleaseDate(LocalDate releaseDate) {
        this.releaseDate = releaseDate;
    }
 
    @Column(name = "REGISTER_DATE", nullable = false)
    public LocalDate getRegisterDate() {
        return registerDate;
    }
 
    public void setRegisterDate(LocalDate registerDate) {
        this.registerDate = registerDate;
    }
 
    @Column(name = "TOTAL_EXAMPLARIES")
    public Integer getTotalExamplaries() {
        return totalExamplaries;
    }
 
    public void setTotalExamplaries(Integer totalExamplaries) {
        this.totalExamplaries = totalExamplaries;
    }
 
    @Column(name = "AUTHOR")
    public String getAuthor() {
        return author;
    }
 
    public void setAuthor(String author) {
        this.author = author;
    }
 
    @ManyToOne(optional = false, cascade = CascadeType.ALL)
    @JoinColumn(name = "CAT_CODE", referencedColumnName = "ID")
    public Category getCategory() {
        return category;
    }
 
    public void setCategory(Category category) {
        this.category = category;
    }
 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.book", cascade = CascadeType.ALL)
    // @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk", cascade =
    // CascadeType.ALL)
    public Set<Loan> getLoans() {
        return loans;
    }
 
    public void setLoans(Set<Loan> loans) {
        this.loans = loans;
    }
 
}
 
@ApiModel(value = "Category Model")
//@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(using = CategoryDTODeserializer.class)
public class CategoryDTO implements Comparable<CategoryDTO> {
    public CategoryDTO() {
    }
 
    public CategoryDTO(String code, String label) {
        super();
        this.code = code;
        this.label = label;
    }
 
    @ApiModelProperty(value = "Category id")
    private Integer id;
 
    @ApiModelProperty(value = "Category code")
    private String code;
 
    @ApiModelProperty(value = "Category label")
    private String label;
 
    public String getCode() {
        return code;
    }
 
    public void setCode(String code) {
        this.code = code;
    }
 
    public String getLabel() {
        return label;
    }
 
    public void setLabel(String label) {
        this.label = label;
    }
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    @Override
    public int compareTo(CategoryDTO o) {
        return label.compareToIgnoreCase(o.label);
    }
}
 
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(using = BookDTODeserializer.class)
public class BookDTO implements Comparable<BookDTO> {
    @ApiModelProperty(value = "Book id")
    private Integer id;
 
    @ApiModelProperty(value = "Book title")
    private String title;
 
    @ApiModelProperty(value = "Book isbn")
    private String isbn;
 
    @ApiModelProperty(value = "Book release date by the editor")
    private LocalDate releaseDate;
 
    @ApiModelProperty(value = "Book register date in the library")
    private LocalDate registerDate;
 
    @ApiModelProperty(value = "Book total examplaries")
    private Integer totalExamplaries;
 
    @ApiModelProperty(value = "Book author")
    private String author;
 
    @ApiModelProperty(value = "Book category")
    private CategoryDTO category;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getIsbn() {
        return isbn;
    }
 
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
 
    public LocalDate getReleaseDate() {
        return releaseDate;
    }
 
    public void setReleaseDate(LocalDate releaseDate) {
        this.releaseDate = releaseDate;
    }
 
    public LocalDate getRegisterDate() {
        return registerDate;
    }
 
    public void setRegisterDate(LocalDate registerDate) {
        this.registerDate = registerDate;
    }
 
    public Integer getTotalExamplaries() {
        return totalExamplaries;
    }
 
    public void setTotalExamplaries(Integer totalExamplaries) {
        this.totalExamplaries = totalExamplaries;
    }
 
    public String getAuthor() {
        return author;
    }
 
    public void setAuthor(String author) {
        this.author = author;
    }
 
    public CategoryDTO getCategory() {
        return category;
    }
 
    public void setCategory(CategoryDTO category) {
        this.category = category;
    }
 
    @Override
    public int compareTo(BookDTO o) {
        return title.compareToIgnoreCase(o.getTitle());
    }
 
    public BookDTO() {
        super();
    }
 
    public BookDTO(String title, String isbn, LocalDate releaseDate, Integer totalExamplaries, String author,
            CategoryDTO category) {
        super();
        this.title = title;
        this.isbn = isbn;
        this.releaseDate = releaseDate;
        this.totalExamplaries = totalExamplaries;
        this.author = author;
        this.category = category;
    }
 
 
}
 
public class BookDTODeserializer extends StdDeserializer<BookDTO> {
 
    @Override
    public BookDTO deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = p.getCodec().readTree(p);
        String title = node.get("title").asText();
        String isbn = node.get("isbn").asText();
        String string = "2018-04-10T04:00:00.000Z"; // 2021-01-05T00:00:00.000Z
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
        LocalDate date = LocalDate.parse(string, formatter);
        System.out.println("convertir date test : " + date);
        LocalDate releaseDate = LocalDate.parse(node.get("releaseDate").asText(), formatter);
        System.out.println("releaseDate  : " + releaseDate);
        Integer totalExamplaries = (Integer) ((IntNode) node.get("totalExamplaries")).numberValue();
        String author = node.get("author").asText();
        String codeCategory = "M";
        String labelCategory = "Mathematique";
 
        return new BookDTO(title, isbn, releaseDate, totalExamplaries, author,
                new CategoryDTO(codeCategory, labelCategory));
        // return null;
    }
 
    public BookDTODeserializer(Class<?> vc) {
        super(vc);
        // TODO Auto-generated constructor stub
    }
 
    public BookDTODeserializer(JavaType valueType) {
        super(valueType);
        // TODO Auto-generated constructor stub
    }
 
    public BookDTODeserializer(StdDeserializer<?> src) {
        super(src);
        // TODO Auto-generated constructor stub
    }
 
    public BookDTODeserializer() {
        super(BookDTO.class);
    }
 
}
 
public class CategoryDTODeserializer extends StdDeserializer<CategoryDTO> {
 
    @Override
    public CategoryDTO deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        JsonNode node = p.getCodec().readTree(p);
        String codeCategory = node.get("code").asText();
        String labelCategory = node.get("label").asText();
        return new CategoryDTO(codeCategory, labelCategory);
    }
 
    public CategoryDTODeserializer(Class<?> vc) {
        super(vc);
        // TODO Auto-generated constructor stub
    }
 
    public CategoryDTODeserializer(JavaType valueType) {
        super(valueType);
        // TODO Auto-generated constructor stub
    }
 
    public CategoryDTODeserializer(StdDeserializer<?> src) {
        super(src);
        // TODO Auto-generated constructor stub
    }
 
    public CategoryDTODeserializer() {
        super(CategoryDTO.class);
    }
 
}
 
Controller :
 
@RestController
@RequestMapping("/rest/book/api")
@Api(value = "Book Rest Controller: contains all operations for managing books")
public class BookRestController {
    public static final Logger LOGGER = LoggerFactory.getLogger(BookRestController.class);
 
    @Autowired
    private BookServiceImpl bookService;
 
    @GetMapping("/allbooks")
    @ApiOperation(value = "List all book books of the Library", response = List.class)
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Ok: successfully listed"),
            @ApiResponse(code = 204, message = "No Content: no result founded"), })
    public ResponseEntity<List<BookDTO>> getAllBooks() {
        List<Book> books = bookService.getAllBooks();
        if (!CollectionUtils.isEmpty(books)) {
            // on retire tous les élts null que peut contenir cette liste
            books.removeAll(Collections.singleton(null));
            List<BookDTO> bookDTOs = books.stream().map(book -> {
                return mapBookToBookDTO(book);
            }).collect(Collectors.toList());
            return new ResponseEntity<List<BookDTO>>(bookDTOs, HttpStatus.OK);
        }
        return new ResponseEntity<List<BookDTO>>(HttpStatus.NO_CONTENT);
    }
 
    // @PostMapping("/addBook")
    @RequestMapping(value = "/addBook", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
    @ApiOperation(value = "Add a new Book in the Library", response = BookDTO.class)
    @ApiResponses(value = { @ApiResponse(code = 409, message = "Conflict: the book already exist"),
            @ApiResponse(code = 201, message = "Created: the book is successfully inserted"),
            @ApiResponse(code = 304, message = "Not Modified: the book is unsuccessfully inserted") })
    public ResponseEntity<BookDTO> createNewBook(@RequestBody BookDTO bookDTORequest) {
        // , UriComponentsBuilder uriComponentBuilder
        Book existingBook = bookService.findBookByIsbn(bookDTORequest.getIsbn());
        if (existingBook != null) {
            return new ResponseEntity<BookDTO>(HttpStatus.CONFLICT);
        }
        Book bookRequest = mapBookDTOToBook(bookDTORequest);
        Book book = bookService.saveBook(bookRequest);
        if (book != null && book.getId() != null) {
            BookDTO bookDTO = mapBookToBookDTO(book);
            return new ResponseEntity<BookDTO>(bookDTO, HttpStatus.CREATED);
        }
        return new ResponseEntity<BookDTO>(HttpStatus.NOT_MODIFIED);
 
    }
 
 
    private BookDTO mapBookToBookDTO(Book book) {
        ModelMapper mapper = new ModelMapper();
        BookDTO bookDTO = mapper.map(book, BookDTO.class);
        if (book.getCategory() != null) {
            bookDTO.setCategory(new CategoryDTO(book.getCategory().getCode(), book.getCategory().getLabel()));
        }
        return bookDTO;
    }
 
 
    private Book mapBookDTOToBook(BookDTO bookDTO) {
        ModelMapper mapper = new ModelMapper();
        Book book = mapper.map(bookDTO, Book.class);
        book.setCategory(new Category(bookDTO.getCategory().getCode(), ""));
        book.setRegisterDate(LocalDate.now());
        return book;
    }
}

另外,我还有一个问题,如何在 BookDTODeserializer 中检索 Code 和 Category 类标签?

有解决这个问题的办法吗?

【问题讨论】:

    标签: java angular spring spring-boot hibernate


    【解决方案1】:

    每次尝试创建新书时,您都会在 mapBookDTOToBook 中创建一个新的 Category。将新书保存到数据库时,代码还会尝试创建一个新类别。

    在保存图书实例之前尝试从数据库中加载类别:

    book.setCategory(categoryService.findCategoryByCode(bookDTO.getCategory().getCode());
    

    请注意示例假设:

    • 存在服务CategoryService 以从数据库中加载类别
    • 结果始终为非空

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-12
      • 1970-01-01
      • 2016-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多