I was working on a project recently where I hit a peculiar problem. The problem was I wanted to map the same entity to different tables dynamically. In my case, I was using Postgres and I had an entity like the one below.

@Entity(name = "form_entry")
public class FormEntry {

    // Other Stuff

    @NotNull
    private ObjectNode data;
    
    // Other Stuff
}

As you can see the entity is mapped to a static table name form_entry. What I wanted was to have a form_entry table for each form that was created, say form_1_entry, form_2_entry etc.

The problem however is that JPA doesn't provide any mechanism to do this. To top it off I was using Spring JPA Repositories. So unless absolutely required I wasn't writing any queries or even using the entity manager directly.

Of course I could write the queries but I didn't want to do that either. So I began prodding.

Interceptors to the rescue

public class HibernateInterceptor extends EmptyInterceptor {

    @Override
    public String onPrepareStatement(String sql) {
        Long formId = RequestContextHolder.getFormId();
        if (formId != null) {
            return sql.replaceAll("form_entry", 
                                 "form_" + formId + "_entry");
        }
        return sql;
    }

}

As you can see all you need to do is use the HibernateInterceptor and change the prepared statement to replace form_entry to form_1_entry etc. and JPA wouldn't even know what hit it.

Ok, but what is the RequestContextHolder

    @GetMapping(value = "/{formEntryId}")
    public FormEntry getFormEntry(@PathVariable Long formId, 
                                  @PathVariable Long formEntryId) {
        RequestContextHolder.setFormId(formId);
        return formEntryService.getFormEntry(formId, formEntryId);
    }

RequestContextHolder is just a thread-safe class that holds the form id (amongst other things). So you will have to set the form id before you call any JPA methods or use the Entity Manager. The name because i was using this in a Web App.

Please be advised though I did not end up using this solution, I decided to stick with a single table and instead choosing to add an indexed form id column.