Отношение один ко многим поддерживает чтение и удаление, но не вставки - PullRequest
0 голосов
/ 24 января 2019

Я бы хотел расширить требования, указанные в более раннем посте , для поддержки удаленийУ нас есть два объекта модели данных - организация и отдел, разделяющие отношения один ко многим.С помощью приведенного ниже сопоставления я могу прочитать список отделов из объекта организации.Я не добавил свойство каскада 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

    }

}

Ответы [ 3 ]

0 голосов
/ 24 января 2019

См. Комментарии к коду о причинах сбоя:

@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()); 
    }
}

Правильное исправление состоит в том, чтобы гарантировать, что модель в памяти всегда поддерживается правильно путем инкапсуляцииоперации добавления / удаления / установки и предотвращения прямого доступа к коллекциям.например,

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);
        }
    }
}
0 голосов
/ 24 января 2019

Попробуйте этот код,

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

если возникнут проблемы, сообщите

0 голосов
/ 24 января 2019

Вы можете попытаться добавить каскад, чтобы ограничить удаление операций только из организации в отдел:

@OneToMany(mappedBy = "organization", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Department> departments;

Обратите внимание, что если у вас есть ограничения для зависимых / внешних ключей для объекта отдела, то вам потребуетсячтобы каскадно удалить операции для этих зависимых объектов.

Вы можете прочитать это руководство, оно хорошо объясняет каскадные операции: https://vladmihalcea.com/a-beginners-guide-to-jpa-and-hibernate-cascade-types/

...