How to map dynamically created table in Hibernate? - java

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

Related

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.

how do you easily create tables in spring mvc

I have a spring mvc project that needs to create a bunch of tables. The source of the table data is from a non-SQL, remote data source that isn't available until after the user logs in. I can create dummy rows in DataConfiguration.initDatabase and then truncate each table. If I don't do that, then when I try to insert data in other places in the code, the reference to the repository is null.
Since I have quite a number of tables and they use referential integrity, is there a way to declare them in such a way that they are automatically created without actually inserting any data?
I am using Java configuration.
The tables were apparently created after all. Even when I looked in H2, I couldn't find them. Turns out I was looking in the default H2 connection "jdbc:h2:~/test" rather than "jdbc:h2:mem:testdb".

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 persist entity to two different tables using Spring+Hibernate

I imagine this pertains to Hibernate only (I'm just now beginning to use these two frameworks). I have an application that tracks sessions for users. While a session is active, the Session entity is stored in a table for active sessions. When the user goes offline and the session ends, the session is moved to a secondary historical table.
How do I achieve this with Hibernate? Right now I have a Session.hbm.xml file that maps a Session object to the active sessions table. Can I map it to a secondary table and somehow specify to which table I want it to persist when I call saveOrUpdate?
My reputation currently won't allow me to answer my own question this quickly. I don't want anyone to waste their time on this though, since I found an answer, so I'm posting it here as an edit.
I can do this by making use of the entity-name attribute in a mapping file. I created a second mapping, identical to Session.hbm.xml, called HistoricalSession.hbm.xml. In this new mapping file I reference the same Session class, but add:
entity-name="HistoricalSession"
Then I map the object to my second (historical) table just like normal. Calling save() or saveOrUpdate() defaults to using the classname as the entity-name, and saves in my primary table as before. Now, when I want to save a session to the historical table I use the Hibernate API overrides that allow you to specify an entity-name:
saveOrUpdate("HistoricalSession",session);
This accomplishes exactly what I want without need to create another Java class for historical sessions
I can do this by making use of the entity-name attribute in a mapping file. I created a second mapping, identical to Session.hbm.xml, called HistoricalSession.hbm.xml. In this new mapping file I reference the same Session class, but add:
entity-name="HistoricalSession"
Then I map the object to my second (historical) table just like normal. Calling save() or saveOrUpdate() defaults to using the classname as the entity-name, and saves in my primary table as before. Now, when I want to save a session to the historical table I use the Hibernate API overrides that allow you to specify an entity-name:
saveOrUpdate("HistoricalSession",session);
This accomplishes exactly what I want without need to create another Java class for historical sessions
A couple of way to do this could be:
Use a database trigger when the session gets expired the trrigger will move the row to the historical table.
You can create a HistoricalSession extends Session and then do a second mapping for HistoricalSession and write the code to delete from Session and insert into historical session.
Your need sounds like more of an audit like.
Check project Hibernate Envers it might help solve your case in a better way.

Categories