Spring Boot + JPA + Hibernate different table name prefix - java

I am working on a multi-tenanted application (with old database structure) where I have a common user table and set of tables based on the access permission.
For example if the user can work with invoice of different companies C1 and C2, the database contains a tables with name C1_invoice and C2_invoice.
I am able to achieve adding prefix with one company using org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
So I can access C1_invoice table. But how can I choose the prefix C1 or C2 dynamically?

You could use a variation of this approach.
It is basically using hibernate's multitenancy features in Spring Data by providing a custom MultiTenantConnectionProvider. The connection provider reads connection details from a map of data sources. You could provide a different value for the hibernate.physical_naming_strategy in each of the data sources. I'm not sure if there's a way to specify the prefix for each data source as a property, though. You could end up with a separate subclass of the PhysicalNamingStrategy for each tenant. Could be gruesome.
What DB are you using? Alternatively, you could resolve the issue by providing a schema per each tenant, and aliasing their tables from the default schema using unprefixed names, something along the lines of:
CREATE SYNONYM C1.INVOICE FOR DEFAULT.C1_INVOICE;
This way, you could use Hibernate's standard MultitenancyStrategy.SCHEMA strategy.

Related

Spring Hibernate JPA - Using many schemas

The company I am working for stores their client data in a separate database schema for each client. They indicate that this cannot be changed at this time. Is there an efficient way to pull data and update data in all schemas without configuring a connection for each schema? Everything I can find when I search seems to be talking about using one or a couple of schemas, but I need to use many (100+) simultaneously.
In any given persistence context, each JPA entity class is mapped to a specific base table. Whether and how easily you can access multiple schemas via a single DB connection is a function of your DBMS, your JDBC driver, and perhaps your particular database, but even a combination that in general supports the kind of access you would need will still not allow you to map the same entity class to multiple distinct base tables in the same persistence context.
You might be able to use the same entity classes for different clients by associating a different persistence context with each client, but that will not allow you use the same DB connection for all of them. Thus, if using the same connection were possible for you at all, it would require different entity classes per client.
Have you considered creating a new DB user and creating SYNONYMS for each of the tables in the separate database schemas ?
You could then map JPA entitys to the SYNONYM names that you have created..
Using this approach you could still use the one DB connection but with SYNONYMS to the DB tables in the other schemas...

How to alter databases tables at run time using JPA?

I am creating CRUD application for customer . and he asked me to allow him to create new Fields in a form (database columns) without restarting the application server. which JPA implementation should I use (hibernate , eclipselink ,openjpa)
to accomplish this task and how it will be done?
Please don't change the database schema at runtime.
Assuming, you would add a column to a table. Then you have to add a field in your entity class, too. And the mapping. So you not only have to change a Java class at runtime, at next application start, you must add this field again. No JPA implementation can do that.
Of course, you can use plain JDBC. And instead of entity classes with concrete fields you can use something like a map for your dynamic fields. But you should adapt all your SQL queries according to the presence of dynamic fields. So you need a way to store the information, which dynamic fields are already created. You can do this with another table or use the table meta information. Additionally you have to manage user defined field names. E.g you should avoid SQL keywords, there is a maximum field name length, etc.
Or you can step back and rethink your approach. You have a requirement: Static given fields in a form and the possibility to create dynamic fields.
Why not adapt your data model to that requirement? A data model which is able to handle dynamic form fields. Such flexible datamodel wouldn't need dynamic SQL table field creation. (And JPA can handle that, too.)
The simplest example would be a table with two columns. One for the field name and one for the value (as string). Maybe a third one to identify the type.
Another alternative would be to use a NoSQL database system like a key value store or a document oriented database.

Dynamic mapping an entity to multiple tables

I just searched for dynamic mapping with eclipselink, I cannot find a solution for my case, now in my system, an entity have 3 versions, one is working/draft (i.e. W100), another is is production (i.e. M100), and remaining one is history version (H100), at any time, we may access both working,production and history versions.
i.e.
Account account = // query from working.
account.setStatus("APPROVED");
account.increaseVersionNo();
myJPAEngine.updateApproved(account); // this step update status to both working and production
//, and W100.PRODUCTION_IPKEY = M100.IPKEY
// (if production version does't exist
//, create a new one with same columns as working version).
//, if increaseVersionNo() called, then we need copy old 'M'- production record to 'H' history version table.
//, my JPA engine need access both 'W'/'M'/'H' tables at same time by passing a parameter to JPA API metadata classes by ThreadLocal or other related workaround.
Does eclipselink (or Hibernate) support this? my dynamic mapping accept a parameter to decide which table is used, that is to say this is an interactive dynamic mapping.
Can and how we plugin some customization into eclipselink metadata classes?
Thanks.
SQL Table name is mapped into an entity class using xml configuration / annotation, so I doubt you can change it at runtime
The only way I can think of is by using entity manager native query, eg:
String sql = "select xyz from " + tableName;
List<MyEntity> reuslt = em.createNativeQuery(sql, MyEntity.class).getResultList();
I would create three subclasses of Account (DraftAccount, ActiveAccount, HistoricalAccount) and use a #MappedSuperclass or TABLE_PER_CLASS inheritance. To switch the account you would delete the old account and create a new one.
Another alternative is to to define a VIEW to make the three tables look like one (or actually change to have one table with a TYPE column).
You can customize EclipseLink operations using custom SQL, stored procedure or query redirectors, but I would recommend changing your model over faking it underneath.

Using criteria-api to dynamic tables

I use criteria-api to made sql query to the database and it work very fine.
But now I need to use dynamic tables , where some tables can be create or destroyed and some column can be add or removed.
I want to manage this entityties in dynamicBean of apache, then I can create bean and edit the column.
How can I made a sql sentece using criteria-api if the bean is not in the file persistence.xml and if it is a dynamic bean?
Not sure on dynamic beans, but you may wish to investigate EclipseLink's dynamic entity support,
http://www.eclipse.org/eclipselink/documentation/2.4/solutions/softwareasaservice002.htm#BABFJDCF

How to map dynamically created table in Hibernate?

I am working on a web application. We are using Hibernate as ORM in our project. Actually, our application creates some tables dynamically based on user selection. The user can select table name, column name and then s/he can import data from a csv file. So my question is: how to map this dynamically created table with Hibernate and Java objects?
It can be done dynamically, but it's somewhat messy:
You'll need to dynamically alter Hibernate's Configuration object before SessionFactory is built. If you're using Spring, this can be done by overriding postProcessAnnotationConfiguration() method of AnnotationSessionFactoryBean; otherwise you'll just need to do it using your Configuration object prior to invoking buildSessionFactory() on it.
If you need to do this without application restart, you're looking at either rebuilding your SessionFactory (which means your users will have to wait until that's done) or using a separate SessionFactory instance specifically dedicated to your custom classes (which is next to impossible if your custom classes need to reference your built-in classes).
You can get access to class / table mappings via configuration.getMappings(). You will then need to create a new table mapping via Table API and add it to configuration via addTable(). Same thing will have to be done with PersistentClass which represents a class mapping. If you're using the same class to represent multiple entities (e.g. map multiple tables) make sure to use unique entity names for each. You'll have to do this (alter the configuration) on every app restart.
How much of the tables are dynamically created? Are the tables similar and you just change the database name?
Here is a discussion of changing the table name:
http://www.experts-exchange.com/Programming/Languages/Java/J2EE/Frameworks/Spring/Q_24237099.html
If you are completely building a new table, can you use a view, and just direct people to a view?
Why are you using Hibernate for this, rather than just dynamically creating queries in JDBC?
The database solution - you can create a view and point it to one table or another (assuming the structure is identical).
CREATE VIEW HIBERNATE_NAME
as
SELECT * FROM TABLE_A
or
CREATE VIEW HIBERNATE_NAME
as
SELECT * FROM TABLE_B
You would need you application to execute native SQL (DDL),
however this should be easier than Hibernate hacks

Categories