Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA Hibernate Dynamic entity mapping & persistence at runtime

Basically we have a spring boot application that requires that the user can define his/her own set of fields and that these fields should be persisted in their own class/table through JPA/Hibernate at runtime. These classes will be generated dynamically through bytebuddy.

All that should be done dynamically without having to restart the application. The Hibernate Dynamic mapping is not an option, since we will be creating new classes entirely and re-map them.

I have also considered an EAV model but that will not work since we will need separate tables for each set of data so the JSON cannot be mixed in the same table.

The first solution that I'm considering is to proxy the EntityManagetFactory and when we have a new entity to map , I'll re-create the EntityManagetFactory and add the new mapped entity to it, I'll also have the hbm2ddl.auto set to "update" in order to ensure that the new tables scheme will get created.

Problem is that I don't know what other classes that might need proxying, I believe I'll have to proxy the Hibernate SessionFactory but I'm not sure how many other classes that will need to be re-created and proxied and I believe that this is a complex path to go.

The other solution is to mix between the SQL and NoSQL solution by using Hibernate OGM, but in that case I'll loose any relationship that I can have with the existing SQL entities and I'm not in favor of running a second NoSQL DB.

is there are any other solutions I can explore ?

Edit:

I would use bytebuddy in order to generate the new classes dynamically and they would have the @Entity annotation, the generated classes are written into a temporary jar file ( e.g. /tmp/myjar.jar )

Using a BeanPostProcessor.postProcessAfterInitialization I would replace the LocalContainerEntityManagerFactoryBean with a proxy class.

Also I used the LocalContainerEntityManagerFactoryBean .setPersistenceUnitPostProcessors to add an extra processor that would process the classes from the newly created jar

So now after creating the new class with bytebuddy I would manually call the LocalContainerEntityManagerFactoryBeanProxy.afterProperties that does all the job of bootstrapping the JPA and hibernate layer , I do also set the "hibernate.hbm2ddl.auto" property to "update" so that the schema would be created ( I know that this is risky to be done in a production environment )

like image 784
Ramy Siha Avatar asked Nov 16 '17 13:11

Ramy Siha


1 Answers

Hibernate maps entities to tables, and the metadata is built during bootstrap. So, you can't modify it on the fly while the application is running.

However, as long as you keep on adding new tables without modifying the existing structure, you can address this issue at the architecture level:

  1. You make the class changes you need.
  2. You build the project artifacts.
  3. You deploy the new project artifacts to a new server.
  4. You switch traffic from the old server instance to the new one from the load balancer without any downtime.

Or, just use a NoSQL database like MongoDB with Hibernate OGM since your requirements do not fit very well into a relational database anyway.

But, if you already use a RDBMS, then it's simpler to just use JSON instead of switching to a NoSQL database just for that reason.

like image 74
Vlad Mihalcea Avatar answered Oct 10 '22 03:10

Vlad Mihalcea