基于存储库方法在 JPA 中以不同方式处理数据

Handling data differently in JPA based on repository methods

在 Java Spring 应用程序中,我有一个 class 类似于以下内容:

class MyModel {
    // other properties here
  
    private Boolean accessAllowed;

    public Boolen isAccessAllowed() {
       return accessAllowed;
    }

    public void setAccessAllowed(Boolean accessAllowed) {
       this.accessAllowed = accessAllowed;
    }

    public void updateAccessAllowedForResponse() {
       // business logic to update `accessAllowed` only for read methods of repository
    }

    public void updateAccessAllowedForSave() {
       // business logic to update `accessAllowed` only for write methods of repository
    }
}

我们的想法是我们在数据库中使用三个值,即 nulltruefalse 并使用空值作为“默认值”,即用户没有进行选择。因此,如果 DB 中的值为空,我们 return 根据某些业务逻辑 truefalse

问题是这个值只是为了响应或其他应用程序在“内存中”更新,但是 updateAccessAllowedForResponse() 之后实体的变化不应该在数据库中持续存在。

目前,我从存储库中的 Hibernate 会话中取消附加实体,例如

class MyRepository extends GenericRepository<MyModel> {
    public MyModel get(Long id) {
        MyModel instance = super.get(id);
        Session session = entityManager.unwrap(Session.class);
        session.evict(instance);
        instance.updateAccessAllowedForResponse();
        return instance;
    }
    public MyModel merge(MyModel instance) {
        instance.updateAccessAllowedForSave()
        return super.merge(instance);
    }
}

这可行,但是上述方法存在一个大问题:我必须在很多地方重复这个。理想情况下,我希望能够在 MyModel 本身上定义此逻辑。也可以选择使用自定义存储库,但这是一个非常具体的用例,我们没有时间仅为此功能编写自定义存储库。

老实说,我是 Java / Spring 的新手。所以我希望有一些我无法通过谷歌搜索找到的方法。

您可以使用 Spring 事务来完成此操作,方法是创建两个单独的保存方法,一个具有 Spring Transactionalisolation = Isolation.SERIALIZABLE,另一个没有。所以你的意思是你想强迫用户使用特定的保存点,无论他们是否想在交易中用不同的对象做其他事情。在这种情况下,强制提交,刷新,调用 yourPersistenceService.saveSecondaryObject(x) 什么的,然后你说 yourPersistenceService.savePrimaryObject(y) 之前总是需要调用。或者,对于 MyModel 对象,通过更新触发方法执行 pre-save 和 post-save。这应该由 Hibernate 自动发生,因此您有机会在其中跟踪此字段更改,并在持久化后设置字段。这与我遇到的 read-only 字段的情况相同,这些字段只需要为输出复制(数据库是 Postgres 12,我制作了一个副本 table 只是从一个到 read-only table 在一个便宜的触发器上。这样,每次模型更改时,它都会触发 Postgres 上的作业以更新 table)。

    public MyModel get(Long id) {
        MyModel instance = super.get(id);
        Hibernate.initialize(instance.accessAllowed);
        instance.flush();
        return instance;
    }

作为第三种选择,您可以让控制器处理所有这些,接收 JPA 对象,设置字段,然后将其发送到 JSP,而无需刷新或 re-loading任何东西。