Ich habe mal ein wenig gegraben...
Wir haben eine Entity. Das ist die einzige Klasse, die wir mappen!
Code:
package domain;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PostLoad;
import javax.persistence.Transient;
@Entity
public class AbstractEntity {
@Id
@Column(name = "ABSTRACT_ID")
private Long id;
@Transient
private Map<String, Object> dynamicAttributes = null;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@PostLoad
public void postload() {
if (dynamicAttributes == null || dynamicAttributes.isEmpty()) {
dynamicAttributes = new HashMap<String, Object>();
}
}
public Map<String, Object> getDynamicAttributes() {
return dynamicAttributes;
}
public void setDynamicAttributes(Map<String, Object> dynamicAttributes) {
this.dynamicAttributes = dynamicAttributes;
}
public void setDynamicProperty(String propertyName, Object value) {
dynamicAttributes.put(propertyName, value);
}
@Override
public String toString() {
return "AbstractEntity [dynamicAttributes=" + dynamicAttributes
+ ", id=" + id + "]";
}
}
Ich habe mich hier auf einen Long für die ID festgelegt, weil wir in unserem Modell nur generische, über eine Sequence erzeugte IDs haben.
Code:
package test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.criterion.Restrictions;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.SimpleValue;
import hibernate.HibernateUtil;
import domain.AbstractEntity;
public class TestAbstract {
/**
* @param args
*/
@SuppressWarnings("unchecked")
public static void main(String[] args) {
AnnotationConfiguration cfg = HibernateUtil.getConfiguration();
PersistentClass clazz = cfg
.getClassMapping(domain.AbstractEntity.class
.getName());
// Lege den Namen der neuen Tabelle fest
String tablename = "TABLE_BLA";
clazz.getIdentifier().getTable().setName(tablename);
// Legt den Spaltennamen der ID-Spalte fest
Property identifierProperty = clazz.getIdentifierProperty();
Iterator<?> columnIterator = identifierProperty.getColumnIterator();
while (columnIterator.hasNext()) {
Column col = (Column) columnIterator.next();
col.setName("FIRST_ID");
}
// Mappt die Map für die neuen Spalten
Component component = new Component(clazz);
component.setTable(clazz.getTable());
Property dynamicProperty = new Property();
dynamicProperty.setName("dynamicAttributes");
dynamicProperty.setNodeName("dynamicAttributes");
dynamicProperty.setValue(component);
clazz.addProperty(dynamicProperty);
// Legt eine neue Spalte an
Column column = new Column("FIRST_NAME");
column.setLength(50);
clazz.getTable().addColumn(column);
// Setzt den Typ der Spalte als String
SimpleValue value = new SimpleValue();
value.setTable(clazz.getTable());
value.addColumn(column);
value.setTypeName("string");
// Mappt die eigentliche Property auf den Namen "name"
Property property = new Property();
property.setName("name");
property.setNodeName("name");
property.setValue(value);
// Legt die neue Spalte als Paar in der Map ab
component.addProperty(property);
// Legt eine neue Spalte an
Column column2 = new Column("ALTER_P");
column2.setPrecision(2);
column2.setLength(5);
clazz.getTable().addColumn(column2);
// Setzt den Typ der Spalte als String
SimpleValue value2 = new SimpleValue();
value2.setTable(clazz.getTable());
value2.addColumn(column2);
value2.setTypeName("double");
// Mappt die eigentliche Property auf den Namen "alter"
Property property2 = new Property();
property2.setName("alter");
property2.setNodeName("alter");
property2.setValue(value2);
component.addProperty(property2);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction trans = session.beginTransaction();
Criteria crit = session.createCriteria(AbstractEntity.class);
//crit.add(Restrictions.gt("dynamicAttributes.alter", new Double(20)));
List<AbstractEntity> list = crit.list();
for (AbstractEntity entity : list) {
System.out.println(entity);
String old = entity.getDynamicProperty("name");
String newValue = old + " neu";
entity.setDynamicProperty("name", newValue);
Double alter = entity.getDynamicProperty("alter");
entity.setDynamicProperty("alter", new Double(
alter.doubleValue()- 1d));
}
trans.commit();
session.close();
}
}
Da kommen dann Statements wie dieses bei rum:
select this_.FIRST_ID as FIRST1_0_0_, this_.FIRST_NAME as FIRST2_0_0_, this_.ALTER_P as ALTER3_0_0_ from TABLE_BLA this_ where this_.ALTER_P>?
Aus meiner Sicht funktionierts also bis hierher für einfache Datentypen wie String und Double, sowie für einfache PrimaryKeys. (Wie gesagt, alles immer auf unserer internes Modell abgestellt, bei dem bestimmte Voraussetzungen gegeben sind.)