【发布时间】: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