2017-02-06 78 views
0

在双向OneToMany关系中,如何在不调用父母所有孩子的情况下删除孩子?JPA双向OneToMany接力 - 不能删除孩子

由于我的应用程序有点大,我创建了一个示例项目来重新创建问题。我有两个实体,一个父母和一个孩子。

家长:

package com.example.entity; 

import javax.persistence.*; 
import java.util.List; 

@Entity 
public class Parent { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

    @OneToMany(
     mappedBy  = "parent", 
     cascade  = CascadeType.ALL, 
     fetch   = FetchType.LAZY, 
     orphanRemoval = true 
    ) 
    private List<Child> children; 
} 

getter和二传手未显示!

儿童:

package com.example.entity; 

import javax.persistence.*; 

@Entity 
public class Child { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

    @ManyToOne(fetch = FetchType.EAGER) 
    @JoinColumn(name = "parent_id") 
    private Parent parent; 
} 

getter和二传手未显示!

我也有2个Repositorys:

ChildRepository:

package com.example.dao; 

import com.example.entity.Child; 
import org.springframework.data.jpa.repository.JpaRepository; 
import org.springframework.stereotype.Repository; 

@Repository 
public interface ChildRepository extends JpaRepository<Child, Long> {} 

ParentRepsitory:长得一模一样。

现在,我创建了一个测试来重现问题:

RepositoryTest:

package com.example; 

import com.example.dao.ChildRepository; 
import com.example.dao.ParentRepository; 
import com.example.entity.Child; 
import com.example.entity.Parent; 
import org.junit.Assert; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.test.context.junit4.SpringRunner; 

import javax.transaction.Transactional; 
import java.util.Arrays; 

@RunWith(SpringRunner.class) 
@SpringBootTest 
public class RepositoryTest { 
    @Autowired 
    private ChildRepository childRepository; 

    @Autowired 
    private ParentRepository parentRepository; 

    @Test 
    @Transactional 
    public void test() { 
     Parent parent = new Parent(); 
     Child child1 = new Child(); 
     Child child2 = new Child(); 

     parent.setChildren(Arrays.asList(child1, child2)); 

     Assert.assertEquals(0, parentRepository.count()); 
     Assert.assertEquals(0, childRepository.count()); 

     parentRepository.save(parent); 

     Assert.assertEquals(1, parentRepository.count()); 
     Assert.assertEquals(2, childRepository.count()); 

     childRepository.delete(child1); 

     Assert.assertEquals(1, parentRepository.count()); 
     Assert.assertEquals(1, childRepository.count()); 
    } 
} 

然而Child将永远不会被删除,计数将仍然是2!我已经阅读了关于差不多相同问题的很多问题,答案总是一样的:

parent.getChildren().remove(child1); 
parentRepository.save(parent); 

那不可能是这样的吗?如果我的父母有成千上万的孩子,我必须从数据库中获取所有的孩子以删除它们?而他们所有人中最尴尬的是,如果实体没有被删除,为什么地狱没有任何错误?什么是正确的方法呢?完全从父母中删除列表,并始终手动调用孩子,这样就不会有外键?我试图解决这个问题,因为早餐现在,我正在转圈。

编辑:增加休眠日志:

Hibernate: select count(*) as col_0_0_ from parent parent0_ 
Hibernate: select count(*) as col_0_0_ from child child0_ 
Hibernate: insert into parent (id) values (default) 
Hibernate: insert into child (id, parent_id) values (default, ?) 
Hibernate: insert into child (id, parent_id) values (default, ?) 
Hibernate: select count(*) as col_0_0_ from parent parent0_ 
Hibernate: select count(*) as col_0_0_ from child child0_ 
Hibernate: select count(*) as col_0_0_ from parent parent0_ 
Hibernate: select count(*) as col_0_0_ from child child0_ 
+1

问题是,你正在做一个事务。如果您结束您的交易并检查数据库删除应该有效。 – ByeBye

+0

@ByeBye nope很快就对它进行了测试,正如你从添加的hibernate日志中看到的那样,一个删除ist永远不会被触发。 – daputzy

+0

因为你的child1实体与这个新创建的没有关系。在'childRepository.delete(child1)'时刻只是空的实体。 – ByeBye

回答

0

那个孩子脱管的实例(不是持久的对象),而如果你调试,它不应该有它的ID。

我的问题是你为什么创建新的对象只是为了删除它?如果您可以确定哪个孩子在被保留之前将被删除,为什么不将它从添加中排除(Arrays.asList(child1, child2))?

或者,如果你只能确定它保存后,这意味着你有办法得到该child1的持久化实例,所以你可以删除这个对象,而不会遇到这种问题。