Как работать с коллекцией связанных сущностей (их изменение не требуется)?

96
30 декабря 2021, 22:40

Есть две сущности (политики паролей и группы):

@Entity
@Table(name = "sys_password_policy", schema = "oauth")
public class SysPasswordPolicyEntity implements Serializable {
    private Long policyId;
    private String policyName;
    private Set<SysGroupEntity> sysGroupsByPolicyId;
// ...
    @OneToMany(mappedBy = "sysPasswordPolicyByPasswordPolicyId", fetch = FetchType.LAZY)
    public Set<SysGroupEntity> getSysGroupsByPolicyId() {
        return sysGroupsByPolicyId;
    }
    public void setSysGroupsByPolicyId(Set<SysGroupEntity> sysGroupsByPolicyId) {
        this.sysGroupsByPolicyId = sysGroupsByPolicyId;
    }
}
@Entity
@Table(name = "sys_group", schema = "oauth")
public class SysGroupEntity implements Serializable {
    private Long groupId;
    private String groupName;
    private SysPasswordPolicyEntity sysPasswordPolicyByPasswordPolicyId;
//...
    @ManyToOne
    @JoinColumn(name = "password_policy_id", referencedColumnName = "policy_id")
    public SysPasswordPolicyEntity getSysPasswordPolicyByPasswordPolicyId() {
        return sysPasswordPolicyByPasswordPolicyId;
    }
    public void setSysPasswordPolicyByPasswordPolicyId(SysPasswordPolicyEntity sysPasswordPolicyByPasswordPolicyId) {
        this.sysPasswordPolicyByPasswordPolicyId = sysPasswordPolicyByPasswordPolicyId;
    }
}

Нужно, чтобы:

  • При создании политики можно было ей назначить какие-то группы (группы при этом не должны создаваться, и у них не должны обновляться никакие поля, кроме sysPasswordPolicyByPasswordPolicyId)

  • При обновлении политики можно было удалить из списка группу, а также добавить её в список (при этом не нужно, чтобы группы удалялись из базы, создавались в базе, и не нужно, чтобы у них в базе обновлялись все поля, кроме sysPasswordPolicyByPasswordPolicyId; нужно, чтобы при удалении из списка значение поля sysPasswordPolicyByPasswordPolicyId становилось null, при добавлении - этому полю присваивалась ссылка на текущую группу)

Как обычно решаются такие задачи? (вроде ситуация стандартная, и часто встречается)

P.S. Пытался искать в интернете, но по моей ситуации сложно что-то найти, а по связанным общим темам пока ничего не нашёл.

PSS Пока реализовано так:

    @Override
    public SysPasswordPolicyEntity persist(SysPasswordPolicyEntity entity) {
        setRelationObjects(entity, false);
        return super.persist(entity);
    }
@Override
    public SysPasswordPolicyEntity update(SysPasswordPolicyEntity entity) {
        setRelationObjects(entity, false);
        return super.persist(entity);
    }
       private void setRelationObjects(SysPasswordPolicyEntity entity, boolean isUpdate) {
        if (entity == null)
            return;
            final Set<SysGroupEntity> sysGroupsFromRest = entity.getSysGroupsByPolicyId();
            if (!isUpdate) {
                sysGroupsFromRest.stream() // добавление нового
                        .filter(Objects::nonNull)
                        .forEach(
                                sysGroupEntity -> {
                                    sysGroupEntity.setSysPasswordPolicyByPasswordPolicyId(entity);
                                    final Long groupId = sysGroupEntity.getGroupId();
                                    if (groupId != null) {
                                        Optional.ofNullable(sysGroupDao.findById(groupId))
                                                .ifPresent(sysGroupEntityfromDB -> {
                                                    sysGroupEntityfromDB.setSysPasswordPolicyByPasswordPolicyId(entity); 
                                                    sysGroupDao.update(sysGroupEntityfromDB);
                                                });
                                    }
                                }
                        );
            } else {
                final Session session = getSession();
                final Set<SysGroupEntity> sysGroupEntitiesFromDB = Optional.ofNullable(findById(entity.getPolicyId()))
                        .map(entityFromDB -> {
                            session.evict(entityFromDB);
                            return entityFromDB;
                        })
                        .map(SysPasswordPolicyEntity::getSysGroupsByPolicyId)
                        .orElse(Set.of());
                sysGroupEntitiesFromDB.stream()
                        .filter(Objects::nonNull)
                        .filter(Predicate.not(sysGroupsFromRest::contains))
                        .forEach(
                        sysGroupEntityFromDB -> 
                                Optional.ofNullable(sysGroupDao.findById(sysGroupEntityFromDB.getGroupId()))
                                        .ifPresent(sysGroupEntityfromDB -> {
                                            session.evict(sysGroupEntityfromDB.getSysPasswordPolicyByPasswordPolicyId());
                                            sysGroupEntityfromDB.setSysPasswordPolicyByPasswordPolicyId(null);
                                            sysGroupDao.update(sysGroupEntityfromDB);
                                        })
                );
                sysGroupsFromRest.stream()
                        .filter(Objects::nonNull)
                        .filter(Predicate.not(sysGroupEntitiesFromDB::contains))
                        .forEach(sysGroupEntityFromREST -> {
                            Optional.ofNullable(sysGroupEntityFromREST.getGroupId())
                                    .map(sysGroupDao::findById)
                                    .ifPresent(sysGroupEntityfromDB -> {
                                        sysGroupEntityfromDB.setSysPasswordPolicyByPasswordPolicyId(entity);
                                        sysGroupDao.update(sysGroupEntityfromDB);
                                    });
                });
            }
    }
Answer 1

Судя по описанной структуре основная сущность - группа. Данные храняться в поле sysPasswordPolicyByPasswordPolicyId для писанной связи - поэтому вы назначаете политику группе а не наоборот.

Соответственно когда вы меняете политику, то это не должно менять ссылки на нее.

Если надо поменять ссылку на политику, то это по сути отдельная операция где обновляется не политика а группа.

Если по бизнес требованиям надо проделать какую-либо работу с ссылками из-за изменения политики, то эту логику можно вынести в слушатель. Т.е. сохранение политики в конце публикует событие о том что политика изменена, соответствующий слушатель перехватывает это изменение и вызывает необходимый метод в сервисе работы с группами.Таким образом вы не привязываете сервис политики к сервису групп и будут поделены зоны ответственности.

READ ALSO
Как вывести значение?

Как вывести значение?

Есть такая строка

164
Как делить строку

Как делить строку

Задача: считываю файл и у меня там сплошной текст из цифр, пример:

251
Pattern Prototype(Не видит метод)

Pattern Prototype(Не видит метод)

Не виден метод setNameЧто делать, не пойму, все паблик

172
Поиск файлов в каталогах

Поиск файлов в каталогах

Задача: найти файлы в каталоге и подкаталогах, и сохранить в папку result

156