支持读取和删除但不支持插入的一对多关系

我想扩展之前文章中提到的要求以支持删除。我们有两个数据模型对象 - 组织和部门共享一对多关系。通过下面的映射,我可以从组织对象中读取部门列表。我没有添加级联 ALL 属性来限制创建组织时添加部门。


我应该如何修改@OneToMany 注释(可能还有@ManyToOne)以限制部门的插入但级联删除操作,以便在删除组织对象时删除所有关联的部门?


@Entity

@Table(name="ORGANIZATIONS")

public class Organization{


    @Id

    @GeneratedValue

    Private long id;


    @Column(unique=true)

    Private String name;


    @OneToMany(mappedBy = "organization", fetch = FetchType.EAGER)

    private List<Department> departments;



}


@Entity

@Table(name="DEPARTMENTS")

Public class Department{


   @Id

   @GeneratedValue

   Private long id;


   @Column(unique=true)

   Private String name;



   @ManyToOne(fetch = FetchType.EAGER)

   private Organization organization;


}

删除组织的代码就是一行


organizationRepository.deleteById(orgId);

验证这一点的测试用例如下


@RunWith(SpringJUnit4ClassRunner.class)

@DataJpaTest

@Transactional

public class OrganizationRepositoryTests {


    @Autowired

    private OrganizationRepository organizationRepository;


    @Autowired

    private DepartmentRepository departmentRepository;




    @Test

    public void testDeleteOrganization() {

        final organization organization = organizationRepository.findByName(organizationName).get(); //precondition


        Department d1 = new Department();

        d1.setName("d1");


        d1.setorganization(organization);


        Department d2 = new Department();

        d2.setName("d2");


        d2.setorganization(organization);


        departmentRepository.save(d1);

        departmentRepository.save(d2);


//        assertEquals(2, organizationRepository.getOne(organization.getId()).getDepartments().size()); //this assert is failing. For some reason organizations does not have a list of departments


        organizationRepository.deleteById(organization.getId());


        assertFalse(organizationRepository.findByName(organizationName).isPresent());

        assertEquals(0, departmentRepository.findAll().size()); //no departments should be found


    }


}


哆啦的时光机
浏览 114回答 3
3回答

白猪掌柜的

请参阅有关失败原因的代码注释:@RunWith(SpringJUnit4ClassRunner.class)@DataJpaTest@Transactionalpublic class OrganizationRepositoryTests {&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private OrganizationRepository organizationRepository;&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private DepartmentRepository departmentRepository;&nbsp; &nbsp; @PersistenceContext&nbsp; &nbsp; private Entitymanager em;&nbsp; &nbsp; @Test&nbsp; &nbsp; public void testDeleteOrganization() {&nbsp; &nbsp; &nbsp; &nbsp; Organization organization =&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; organizationRepository.findByName(organizationName).get();&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; Department d1 = new Department();&nbsp; &nbsp; &nbsp; &nbsp; d1.setName("d1");&nbsp; &nbsp; &nbsp; &nbsp; d1.setOrganization(organization);&nbsp; &nbsp; &nbsp; &nbsp; Department d2 = new Department();&nbsp; &nbsp; &nbsp; &nbsp; d2.setName("d2");&nbsp; &nbsp; &nbsp; &nbsp; d2.setOrganization(organization);&nbsp; &nbsp; &nbsp; &nbsp; departmentRepository.save(d1);&nbsp; &nbsp; &nbsp; &nbsp; departmentRepository.save(d2);&nbsp; &nbsp; &nbsp; &nbsp; // this fails because there is no trip to the database as Organization&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // (the one loaded in the first line)&nbsp; &nbsp; &nbsp; &nbsp; // already exists in the current entityManager - and you have not&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // updated its list of departments.&nbsp; &nbsp; &nbsp; &nbsp; // uncommenting the following line will trigger a reload and prove&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // this to be the case: however it is not a fix for the issue.&nbsp; &nbsp; &nbsp; &nbsp; // em.clear();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;assertEquals(2,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;organizationRepository.getOne(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;organization.getId()).getDepartments().size());&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; //similary this will execute without error with the em.clear()&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; //statement uncommented&nbsp; &nbsp; &nbsp; &nbsp; //however without that Hibernate knows nothing about the cascacding&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; //delete as there are no departments&nbsp; &nbsp; &nbsp; &nbsp; //associated with organisation as you have not added them to the list.&nbsp; &nbsp; &nbsp; &nbsp; organizationRepository.deleteById(organization.getId());&nbsp; &nbsp; &nbsp; &nbsp; assertFalse(organizationRepository.findByName(organizationName).isPresent());&nbsp; &nbsp; &nbsp; &nbsp; assertEquals(0, departmentRepository.findAll().size());&nbsp;&nbsp; &nbsp; }}正确的解决方法是通过封装添加/删除/设置操作并防止直接访问集合来确保始终正确维护内存模型。例如public class Department(){&nbsp; &nbsp; public void setOrganisation(Organisation organisation){&nbsp; &nbsp; &nbsp; &nbsp; this.organisation = organisation;&nbsp; &nbsp; &nbsp; &nbsp; if(! organisation.getDepartments().contains(department)){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; organisation.addDepartment(department);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}public class Organisation(){&nbsp; &nbsp; public List<Department> getDepartments(){&nbsp; &nbsp; &nbsp; &nbsp; return Collections.unmodifiableList(departments);&nbsp; &nbsp; }&nbsp; &nbsp; public void addDepartment(Department departmenmt){&nbsp; &nbsp; &nbsp; &nbsp; departments.add(department);&nbsp; &nbsp; &nbsp; &nbsp; if(department.getOrganisation() != this){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; department.setOrganisation(this);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}

qq_笑_17

试试这个代码,&nbsp; &nbsp; @OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL)&nbsp; &nbsp; @JoinColumn(name = "organisation_id", referencedColumnName = "id")&nbsp; &nbsp; private List<Department> departments;&nbsp; &nbsp; @ManyToOne(fetch = FetchType.EAGER,ascade = CascadeType.REFRESH,mappedBy = "departments")&nbsp; &nbsp; private Organization organization;如果有任何问题通知

Helenr

您可以尝试添加以限制级联删除操作仅从组织到部门:@OneToMany(mappedBy&nbsp;=&nbsp;"organization",&nbsp;fetch&nbsp;=&nbsp;FetchType.EAGER,&nbsp;cascade&nbsp;=&nbsp;CascadeType.REMOVE,&nbsp;orphanRemoval&nbsp;=&nbsp;true) private&nbsp;List<Department>&nbsp;departments;请注意,如果您对部门实体有依赖/外键约束,那么您还需要将删除操作级联到这些依赖实体。您可以阅读本指南,它很好地解释了级联操作:&nbsp;https ://vladmihalcea.com/a-beginners-guide-to-jpa-and-hibernate-cascade-types/
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java