Проверьте, есть ли ссылка на объект, чтобы предотвратить мягкое удаление без изменения базы данных. - PullRequest
0 голосов
/ 24 апреля 2018

Как вы видите, я использую мягкое / логическое удаление в моей системе:

Мои объекты:

@Where(clause = "deleted='false'")
public class Person { 
  //...
}

Мои услуги:

@Override
public ServiceResponse DeletePerson (Person entity) {
    ServiceResponse sr = new ServiceResponse<>();

    try {
        sr = ValidateDeletePerson(entity); //Business logic treatment
        if (sr.hasError())
            return sr;

        Person dbEntity = GetPerson(entity.getPersonID());
        dbEntity.setDeleted(true);
        _repository.save(dbEntity);

    } catch (Exception ex) {
        sr.getErrors().add(new ServiceError(ex));
    }

    return sr;
}

Когдапользователь пытается удалить объект - фактически только логическое значение удалено переключено на true в БД, как я продемонстрировал выше, - я хочу проверить, не ссылаются ли на объект другому до выполнения этого логического удаления .

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

Пример. Если Person with ID 5 присоединен к Student, пользователь не может удалить этого человека.

Что такое «Лучшая практика», чтобы предотвратить это ?

Важно РЕДАКТИРОВАТЬ:

1) На человека ссылаются в N таблицах , а не только на ученика, поэтому яисследование общего способа достижения этого (может быть, вы можете сказать hibernate, чтобы проверить это?)

2) Идея состоит в том, чтобы сделать это программно избегая модификаций в DB .

Ответы [ 3 ]

0 голосов
/ 24 апреля 2018

Вы должны проверить эту ссылку через запрос к базе данных.

Например, Если есть таблица Персона и Студент. Если вы удаляете запись в таблице персонажа с ID = 5, вы можете проверить первую ссылку в таблице учеников, используя запрос типа

select count(1) from student where person_id = 5

Если результат> 0, то ошибка в вашем случае, в противном случае продолжить удаление

0 голосов
/ 24 апреля 2018

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

Программно вы можете проверить, создав запрос, который проверяет, существует ли что-то, что ссылается на человека. Я бы использовал JPA QL или HQL или даже Criteria, не нужно опускаться до SQL. Достаточно одного запроса (в сочетании с ИЛИ). Хитрость заключается в том, чтобы найти все объекты и поля для включения в запрос. Для одного случая это просто, сделайте запрос вручную. Вы, вероятно, знаете, на что ссылается Person, если вы не можете искать в IDE или проверить ограничения в базе данных. В общем случае вы хотите сгенерировать этот код или создать его на лету.

Для построения на лету, EntityManager.getMetamodel() даст вам все сущности, так что вы можете просмотреть их атрибуты и посмотреть, есть ли потенциальные ссылки на сущность, с которой вы работаете. Громоздкие.

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

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

0 голосов
/ 24 апреля 2018

Вы можете использовать проверить ограничения на уровне базы данных. Детали специфичны для СУБД, но общая идея для ограничения -

CHECK ((select count(*) from studens 
                         where studens.id= person.id and person.deleted=false) = 0)

Другое решение - архивная таблица

Вы можете избежать этой проблемы, удалив записи и переместив удаленные записи в таблицу person_archive (триггер базы данных может сделать это за вас). Благодаря этому решению внешний ключ сможет защитить целостность данных. Если ваша таблица person большая, это решение также может быть более эффективным, поскольку базе данных придется считывать меньше данных. Я бы использовал таблицу person_archive, если вам не нужно легко восстанавливать удаленные записи из пользовательского интерфейса с удаленным флагом, восстановление - это просто переключение флага. С архивной таблицей восстановление - это больше работы:

  1. выбрать из архива
  2. вставить в таблицу данных
  3. удалить из архива

Если вы не можете изменить базу данных

Если база данных не может быть изменена, то эти проверки должны выполняться внутри ваших классов DAO (вам нужно вызывать запросы для всех связанных объектов). Лучше быть уверенным, что все обращения к базе данных осуществляются этими классами, в противном случае (если кто-то использует прямой SQL), вы можете получить инвариант базы данных, не содержащий true.

...