java - Spring 启动 JPA : How to delete child entity of a Many to One relation

标签 java hibernate jpa spring-data-jpa

我对一个要实现的“简单”案例感到非常疯狂

=> 我想删除通过多对一关系嵌套到父实体的子实体。

很简单不是吗?不幸的是不适合我:-(

下面是我的所有代码和我的尝试

第一个 => 父实体:

@Data
@NoArgsConstructor
@ToString(exclude = "books")
@Entity
public class Category {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToMany(orphanRemoval = true, mappedBy = "category", cascade = CascadeType.ALL,  fetch = FetchType.EAGER)
    private Set<Book> books;

    public Category(String name, Book... books) {
        this.name = name;
        this.books = Stream.of(books).collect(Collectors.toSet());
        this.books.forEach(x -> x.setCategory(this));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Category)) return false;
        Category category = (Category) o;
        return Objects.equals(name, category.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

}

然后是子实体:

@Data
@RequiredArgsConstructor
@NoArgsConstructor
@ToString(exclude = "category")
@Entity
public class Book{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private @NonNull String name;

    @ManyToOne(fetch = FetchType.EAGER)
    private Category category;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(name, book.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

}

2 仓库

public interface BookRepository extends JpaRepository<Book, Integer> {
    @Modifying
    @Query("DELETE Book b WHERE b.category.id = ?1")
    void deleteByCategoryId(int categoryId);

    List<Book> findByCategoryId(int categoryId);
}

public interface CategoryRepository extends JpaRepository<Category, Integer> {
}

以及我正在使用的 Pom.xml 文件的摘录:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!-- PostgreSQL -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

令人惊讶的是,当我尝试删除父实体时,一切正常

int categoryId2 = categoryRepository.saveAndFlush(new Category("B", new Book("B1"), new Book("B2"))).getId();
Category category2 = categoryRepository.findById(categoryId2).get();
categoryRepository.delete(category2);
// Category and the 2 nested books have been removed from the DB

第一次尝试仅删除一本书,结果:

int categoryId = categoryRepository.saveAndFlush(new Category("A", new Book("A1"), new Book("A2"))).getId();
//Category and nested 2 books are perfectly persisted in DB

Category category = categoryRepository.findById(categoryId).get();
Book book = category.getBooks().iterator().next();
int bookId = book.getId();
category.getBooks().remove(book);
//to remove the link in the parent entity
book.setCategory(null);
//to remove the link in the child entity
categoryRepository.flush();
// to persist in the DB 
// At this point, with the help of the orphanRemoval (true) property, i was expecting than the book would have been removed from the DB
// But nothing happened :-( 

第二次尝试“疯狂的解决方法”

int categoryId = categoryRepository.saveAndFlush(new Category("A", new Book("A1"), new Book("A2"))).getId();

Category category = categoryRepository.findById(categoryId).get();
Book book = category.getBooks().iterator().next();
int bookId = book.getId();
category.getBooks().remove(book);
book.setCategory(null);
categoryRepository.flush();
//Same result as the first attempt, nothing happened in the DB

bookRepository.delete(book);
// with this delete call => the link was removed in the DB, book.category_id=null

bookRepository.delete(book);
// with this 2nd delete call => great result => the book entity was removed in the db

有人可以帮助我,给我一个好的方法吗?

最佳答案

试试这个

@OneToMany(orphanRemoval = true, mappedBy = "category", cascade = CascadeType.PERSIST,  fetch = FetchType.EAGER)
private Set<Book> books;

请注意

级联 = CascadeType.PERSIST

希望能有所帮助。
Hibernate Tips: How to delete child entities from a many-to-one association

关于java - Spring 启动 JPA : How to delete child entity of a Many to One relation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60844427/

相关文章:

java - 我可以一次插入多行吗?

java - Criteria.list() 期间出现 org.hibernate.TransientObjectException

java - Spring Data JPA,当我尝试选择DistinctValue时出错

spring-boot - 如何使用 Spring Data JPA(Hibernate) 跨映射表过滤关联实体?

java - 回溯递归问题来解决平衡括号

java - 如何检查正在循环的字符串的最后一个索引

java - TextView,不会设置文本

java - 2D vector 库

hibernate - 哪个是适用于 Scala 和 PostgreSQL 的 Play 框架的最佳数据访问选项?

java - 如何使用旧版本的 hibernate 运行 Spring boot