I have a Data Class for Hibernate associated to a table; imagine the Entity Person like this:
@Entity
@org.hibernate.annotations.Proxy(lazy=false)
@Table(name="Person", schema="MySchema")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class ProfileData implements Serializable {
private static final long serialVersionUID = -844564646821609090L;
public PersonData() {
}
@Column(name="idPerson", nullable=false, unique=true)
@Id
...
I need to create historic tables by years of this table: Person2010, Person2011, Person2012… Is it possible without creating new Data Objects? Maybe by a parameter…? I don´t know.
The Entity class is the same, changing the table name and the constructor.
Another one Architecture, more complez but elegant:
YES, You can change the table names using NamingStrategies:
public class MyNamingStrategy extends DefaultNamingStrategy {
...
@Override
public String tableName(String tableName) {
return tableName+yearSuffixTable;
}
...
}
And, when you wanna to use the _year tables, you must to create a session with Hibernate that override rhe table names:
SessionFactory sessionFactory;
Configuration config = new AnnotationConfiguration()
.configure("hibernate.cfg.xml")
.setNamingStrategy( new MyNamingStrategy () );
sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
For my architecture I create a session by year and store it into Application map for access when I need it.
Thanks.
2
You should try Hibernate Envers for historic data.
6
In Hibernate you map 1 class to 1 table. You can not reuse the same Entity to map several tables dynamically.
Hibernate Envers is a quite good solution for Historic data, but you still will not be able to do what you try (dynamically grow the number of tables without touching mapper Entities).
4
Thanks to @CodeBrickie and @edutesoy I found Envers.
I configure the hibernate config file with AUD suffix and I create new hibernate config files per year (hibernate.cfg.2009.xml, hibernate.cfg.2010.xml, hibernate.cfg.2011.xml…) with the year-suffix.
When I save data, always is audited in AUD table. On January 1, automatically:
- _AUD TABLE is renamed as _PAST_YEAR table.
- A new _AUD table is created.
- A new hibernate.cfg.past_year.xml is created with the new suffix.
When I need to get data, I load the corresponding hibernate configuration file.
Hope this helps to others 🙂
@Table(name="emd_employee_1001")
In the above annotation file name can pass as parameter, for example
x=1001
@Table(name="emd_employee_+x+")
1
Modified at runtime(I think it’s the best way):
Session session = super.getSession();
SQLQuery query = session.createSQLQuery("raw sql");
query.setParameter(":abc", "value");
query.addEntity(Some.class);
return query.list();
1
You can use Hibernate interceptors to change the table in the generated SQL statements.
For your case you can define your table class like this:
@Entity
@org.hibernate.annotations.Proxy(lazy=false)
@Table(name=PersonTableNameReplacer.PLACEHOLDER, schema="MySchema")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class ProfileData implements Serializable {
and define your Hibernate interceptor in a following way:
public class TableNameReplacer extends EmptyInterceptor {
public static final String TABLE_PLACEHOLDER = "{person_table_placeholder}";
@Override
public String onPrepareStatement(String sql) {
if (sql.contains(TABLE_PLACEHOLDER )) {
String replacement = "{your logic to fill proper table name}";
sql = sql.replace(TABLE_SUFFIX_PLACEHOLDER, replacement);
}
return super.onPrepareStatement(sql);
}
Using this approach you’re free to modify generated SQL and replace the table name there as you wish.
I recommend to use good placeholder value which you’re sure will not be a part of actual values being saved to the table (or you can only limit this to select statements if you only read the data).