Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 支持读取和删除但不支持插入的一对多关系_Java_Hibernate_Spring Data Jpa - Fatal编程技术网

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

Java 支持读取和删除但不支持插入的一对多关系,java,hibernate,spring-data-jpa,Java,Hibernate,Spring Data Jpa,我想扩展中提到的要求以支持删除。我们有两个数据模型对象-共享一对多关系的组织和部门。通过下面的映射,我能够从组织对象中读取部门列表。我没有添加cascade ALL属性来限制在创建组织时添加部门 我应该如何修改@OneToMany注释和@ManyToOne以限制插入部门,但级联删除操作,以便在删除组织对象时删除所有关联的部门 @Entity @Table(name="ORGANIZATIONS") public class Organization{ @Id @Generate

我想扩展中提到的要求以支持删除。我们有两个数据模型对象-共享一对多关系的组织和部门。通过下面的映射,我能够从组织对象中读取部门列表。我没有添加cascade 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;

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

@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

    }

}

您可以尝试添加以限制级联仅从组织到部门删除操作:

@OneToMany(mappedBy = "organization", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Department> departments;
请注意,如果您对department实体有依赖项/外键约束,则还需要将删除操作级联到这些依赖实体

您可以阅读本指南,它很好地解释了级联操作:

请参阅有关其失败原因的代码注释:

@RunWith(SpringJUnit4ClassRunner.class)
@DataJpaTest
@Transactional
public class OrganizationRepositoryTests {

    @Autowired
    private OrganizationRepository organizationRepository;

    @Autowired
    private DepartmentRepository departmentRepository;

    @PersistenceContext
    private Entitymanager em;

    @Test
    public void testDeleteOrganization() {
        Organization organization = 
                organizationRepository.findByName(organizationName).get(); 

        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);

        // this fails because there is no trip to the database as Organization 
        // (the one loaded in the first line)
        // already exists in the current entityManager - and you have not 
        // updated its list of departments.
        // uncommenting the following line will trigger a reload and prove 
        // this to be the case: however it is not a fix for the issue.

        // em.clear();

         assertEquals(2,
             organizationRepository.getOne(
               organization.getId()).getDepartments().size()); 

        //similary this will execute without error with the em.clear() 
        //statement uncommented
        //however without that Hibernate knows nothing about the cascacding 
        //delete as there are no departments
        //associated with organisation as you have not added them to the list.
        organizationRepository.deleteById(organization.getId());

        assertFalse(organizationRepository.findByName(organizationName).isPresent());
        assertEquals(0, departmentRepository.findAll().size()); 
    }
}
正确的修复方法是通过封装添加/删除/设置操作和防止 直接访问收藏。 e、 g

试试这个代码

    @OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "organisation_id", referencedColumnName = "id")
    private List<Department> departments;

    @ManyToOne(fetch = FetchType.EAGER,ascade = CascadeType.REFRESH,mappedBy = "departments")
    private Organization organization;

如果有任何问题,则通知

删除失败并出现错误-错误23503:表“ORGANIZATIONS”上的删除导致键2违反外键约束“FKP6W2NOGXIEXHGMUXN1G4MWVHP”。这是添加到department表上的约束,因为它将organization id作为外键。此外,我们无法删除setDepartments方法或从getProjects返回不可修改的列表,因为在创建新部门时,我们会获取其中的组织对象并设置部门列表,以便链接调用work-Department.getOrganization.getDepartments第二点,我不太明白您的意思。第一个问题是mappedBy=organization是否正确,因为发布代码中的字段名为orgYes,所以我更正了mappedBy属性。那是个打字错误。删除操作仍然失败,违反外键约束错误。关于2,一对多关系是双向的,因此organization.getDepartments应该工作,这也应该工作-department.getOrganization.getDepartments。确保内存中模型的正确性应该通过封装来完成,而不是允许客户端代码随机修改集合。对于SQL错误,您应该打开SQL日志记录以查看发生的情况。您还可以尝试使用departmentRepository.saveAndFlushd1;或者从测试类中删除@Transactional以实际触发数据库写入。您需要了解事务上下文中的刷新。删除失败,出现错误-错误23503:表“ORGANIZATIONS”上的删除导致违反键2的外键约束“FKP6W2NOGXIEXHGMUXN1G4MWVHP”。这是添加到department表上的约束,因为它的外键是organization id。您好Andy,您是如何生成数据库的?是手动编写脚本还是使用hibernate.ddl属性自动生成模式?同时,请您也尝试将OrphanRemoving=true添加到注释中。我也将更新我的答案。添加与执行删除/删除操作相关的代码。只要您没有在组织存储库中重新定义继承的deleteById,那么这应该可以工作。
public class Department(){
    public void setOrganisation(Organisation organisation){
        this.organisation = organisation;

        if(! organisation.getDepartments().contains(department)){
            organisation.addDepartment(department);
        }
    }
}

public class Organisation(){

    public List<Department> getDepartments(){
        return Collections.unmodifiableList(departments);
    }

    public void addDepartment(Department departmenmt){
        departments.add(department);

        if(department.getOrganisation() != this){
            department.setOrganisation(this);
        }
    }
}
    @OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "organisation_id", referencedColumnName = "id")
    private List<Department> departments;

    @ManyToOne(fetch = FetchType.EAGER,ascade = CascadeType.REFRESH,mappedBy = "departments")
    private Organization organization;