Как удалить данные, которые имеют внешний ключ в jpa java - PullRequest
1 голос
/ 03 июля 2019

У меня есть вариант использования, у Книги есть одна Категория, и Категория может принадлежать большому количеству Книг. Одна книга может принадлежать нескольким авторам, а автор - нескольким. Итак, вот их отношения:

  1. Book до BookCategory => many-to-one
  2. BookCategory до Book => one-to-many
  3. Book до Author и Author до Book => many-to-many

Итак, у меня 4 таблицы:

  1. book
  2. book_category
  3. author
  4. book_author (book_id, author_id)

Корпус:

  1. если я удалю Book, с таблицей book_category
  2. Если я удаляю Book, Author следует удалить, если Author больше не принадлежит ни одному books. Например, у меня есть book1 и book2 с таким же Author именем John. Если я удалю book1, он не удалит John. Но если я также удалю book2, то John будет удален из таблицы Author. Кроме того, любое удаление книги повлияет на таблицу book_author.

вот как я объявляю сущность

Автор

@Entity(name = "author")
public class Author {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "name", nullable = false)
    private String name;
    @Column(name = "address", nullable = false)
    private String address;
    @ManyToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JsonBackReference
    private Set<Book> book;
}

Книга

@Entity(name = "book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "title", nullable = false)
    private String title;
    @Column(name = "year", nullable = false)
    private String year;
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(
      name = "book_author",
      joinColumns = @JoinColumn(name = "book_id", referencedColumnName = "id"),
      inverseJoinColumns = @JoinColumn(name = "author_id", referencedColumnName = "id"))
    @JsonManagedReference
    private Set<Author> author;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id", referencedColumnName = "id", nullable = false)
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) 
    private BookCategory category;
}

Категория книги

@Entity(name = "book_category")
public class BookCategory {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "category", nullable = false)
    private String category;
}

и вот как я пытаюсь удалить книгу. Просто простой метод. Но после того, как я запустил это, он показывает ошибку с именем org.postgresql.util.PSQLException: ERROR: update or delete on table "book_category" violates foreign key constraint "fk5jgwecmfn1vyn9jtld3o64v4x" on table "book", что похоже на то, что метод пытается также удалить таблицу book_category.

@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public ResponseEntity<?> delete(@PathVariable(value = "id") Long id) throws Exception {
        try {
            bookService.deleteById(id);
            return ResponseEntity.ok().body("delete done");
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }

Тогда как этого добиться? Любая подсказка, пожалуйста?

1 Ответ

0 голосов
/ 03 июля 2019

Я думаю, проблема в cascade = CascadeType.ALL в поле категории в классе Book. Используя CascadeType.ALL, всякий раз, когда вы пытаетесь удалить книгу, ее категория тоже должна быть удалена. Проблема в том, что могут существовать другие экземпляры книг с категорией, которую вы хотите удалить в вашей базе данных. Затем будет выдана ошибка базы данных ограничений.

Итак, я бы рекомендовал использовать cascade = CascadeType.PERSIST или cascade = CascadeType.MERGE в поле категории. Таким образом, при удалении книги категория не будет удалена.

Эта ссылка даст вам лучшее понимание каскадных типов, показывая, как это работает.

Я стараюсь избегать использования каскадов, особенно CascadeType.ALL и CascadeType.REMOVE. Я предпочитаю делать несколько вызовов в слое постоянства, чтобы выполнить какую-то бизнес-задачу (аналогично тем, что были в начале вашего вопроса в перечисленных элементах - если я удалю книгу ..). Кроме того, Spring позволяет вам совершать все вызовы в транзакции, используя @Transactional в любом методе вашего бизнес-уровня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...