Dynamic mapping an entity to multiple tables - java

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.

Related

Spring Boot + JPA + Hibernate different table name prefix

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.

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.

Is it possible to have a composed name table?

We inherit a database and we need to do an API to communicate with it. We are considering the possibility to use JPA / Hibernate, but there is maybe a blocking constraint.
To facilitate maintenance, our predecessors have split a table into multiple with a business parameter.
So, there are some tables named ELEMENT_xxx where xxx is a specific name.
Is it possible to make a JPA entity with a constructor which take the specific name in parameter and then allow to query on the right table?
Thank you
PS:
If not, i think the solution could be to create an entity for each table. But we don't know how many tables they have, and we understood that they can create new.

JPA and unique fields

I have two persistence objects in my app: Things and tags attached to things. The app can generate collections of things with tags attached. Tag objects have a unique name (it doesn't make sense to tag something twice with the same tag).
When inserting a Thing (with tag objects attached) some of these tag objects with the same name maybe already exist in the db. Now here is the part I don't recall about JPA, is there a way to tell JPA that it should not try to add the corresponding objects to the db if it violates the unique constraint? Or is there a way to do this efficiently w/o having to first fetch all objects, then merge the collection in memory and then write everything back?
I'm also wondering if it's possible to persist a whole collection at once or do I have to call persist for every object when using JPA?
I don't know of any way of doing this 'cleanly', neither with JPA nor with Hibernate or any other provider. You can achieve what you want with a custom SQL query though (similar to this question):
#Entity
#Table(name="tag")
#SQLInsert( sql="INSERT INTO tag(name, count) VALUES (?, ?)
ON DUPLICATE KEY UPDATE set count = count + 1")
public class Tag {}
Now you are unfortunately bound to both Hibernate and MySQL. You can vary the sql syntax for other DB:s, and/or use stored procedures, try an update first and insert on failure etc. They all have their drawbacks, so it would be handy if JPA would support this, but alas.
Regarding you second question, JPA support persisting whole object graphs, including collections.

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