Home > Blockchain >  Handling data differently in JPA based on repository methods
Handling data differently in JPA based on repository methods

Time:06-04

In a Java Spring application, I have a class similar to the following:

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
    }
}

The idea is that we use three values in DB i.e. null or true or false and use the null value as "default" i.e. the user didn't make a choice. So if the value is null in DB, we return either true or false based on some business logic.

The problem is that this value is only meant to be updated "in memory" for response or other areas of application, but the change in entity after updateAccessAllowedForResponse() shouldn't persist in DB.

Currently, I de-attach the entity from Hibernate session in the repository, e.g.

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

This works however there is a big problem with the above approach: I have to repeat this in tons of places. Ideally, I would like to be able to define this logic on MyModel itself. There is an option to use a custom repository as well, but this is a very specific use case and we don't have time to write a custom repository just for this functionality.

To be honest, I am new to Java / Spring. So I am hoping there is some way of doing this which I can't find by googling.

CodePudding user response:

You could use Spring transactions to accomplish this, by creating two separate save methods, with one having Spring Transactional with isolation = Isolation.SERIALIZABLE and another without. So what you're saying is that you want to force users to use specific save points, whether they want to do something else in the transaction with different objects, or not. In this case, force commit, flush, call yourPersistenceService.saveSecondaryObject(x) or something, and then you say that yourPersistenceService.savePrimaryObject(y) will always need to be called before. Alternatively, for MyModel object, do pre-save and post-save by update triggering methods. This should happen automatically by Hibernate, so you have an opportunity to track this field change in it, and set the field after persisting. This is the same situation I had with read-only fields that needed to be copied only for output (database was Postgres 12, I made a copy table that just does transactional copy from one to the read-only table on a cheap trigger. In this way, each time model changed, it triggered past the job on Postgres to update the table).

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

As a third option, you could let the controller take care of all this, receiving the JPA object, setting the field, and then sending it to the JSP, without the need of flushing or re-loading anything.

  • Related