检查是否引用了对象以防止软删除而不修改数据库

时间:2018-04-24 19:24:56

标签: java hibernate jpa reference soft-delete

如您所见,我在我的系统上使用软/逻辑删除:

我的实体:

@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个表中引用了人,不仅仅是在Student上,所以我正在研究实现它的通用方法(也许你可以告诉hibernate检查它吗?)

2)我们的想法是以编程方式进行,避免修改数据库

3 个答案:

答案 0 :(得分:1)

您可以在数据库级别使用检查约束。细节是DBMS特定的,但约束的一般想法是

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

其他解决方案 - 存档表

您可以通过删除记录并将已删除的记录移动到person_archive表来避免此问题(数据库触发器可以为您执行此操作)。使用此解决方案,外键将能够保护数据完整性。如果您的person表很大,这个解决方案也可能更有效,因为数据库必须读取更少的数据。 我会使用person_archive表,除非您需要从UI轻松恢复已删除的记录使用已删除的标志,恢复只是翻转标志。使用存档表,还原更多工作:

  1. 从档案中选择
  2. 插入数据表
  3. 从存档中删除
  4. 如果您无法修改数据库

    如果无法更改数据库,那么必须在DAO类中完成这些检查(您需要调用所有相关实体的查询)。最好确保所有数据库访问都是通过这些类进行的,否则(如果有人使用直接SQL),最终可能会导致数据库不变,而不是保持为真。

答案 1 :(得分:1)

您应该通过数据库查询检查此引用。

例如如果有人和学生表。如果要删除ID = 5的人员表上的条目,您可以使用

等查询检查学生表中的第一个参考
select count(1) from student where person_id = 5

如果结果&gt; 0然后在你的情况下它的错误,否则继续删除

答案 2 :(得分:1)

最佳做法是在数据库中执行此操作,而不是争论它。应用程序代码中处理的参照完整性总是会在某些时候中断,只是因为人们倾向于从多个应用程序和手工访问表。

以编程方式,您可以通过构建查询来检查是否存在引用人的内容。我会使用JPA QL或HQL甚至Criteria,不需要下载到SQL。一个查询应该足够(与OR结合)。诀窍是找到要包含在查询中的所有实体和字段。对于一个案例,它很简单,手工查询。您可能知道什么引用Person,如果您不能在IDE中搜索或检查数据库中的约束。在一般情况下,您希望生成此代码或即时构建它。

为了即时构建,EntityManager.getMetamodel()将为您提供所有实体,因此您可以查看其属性并查看是否存在对您正在使用的实体的潜在引用。繁琐。

基于带注释的类生成代码可能很棘手,但如果您知道要检查哪些类(如果您在持久性单元中列出它们),则会变得更加容易。浏览列出的类,阅读注释并生成验证代码。

如果您确实以编程方式以一般方式执行此操作,我将首先手工制作前两个实现。然后我会用它作为生成代码的基础。