Hi. i want to implement 'custom fields' in my projects. I would like to add new column to table during runtime.
But after start i see exception. Can you help?
Code:
org.hibernate.MappingException: property mapping has wrong number of columns: pl.kambu.customfields.data.Person.values type: component[foo,bar]
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:465)
at org.hibernate.mapping.RootClass.validate(RootClass.java:236)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1193)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1378)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at pl.kambu.customfields.AppTest.testApp(AppTest.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)
This is my entity(which i want to extend )
Code:
<hibernate-mapping package="pl.kambu.customfields.data">
<class name="Person">
<id name="id">
<generator class="identity" />
</id>
<property name="name" />
<dynamic-component name="values">
<property name="foo" column="FOO" type="string" />
<property name="bar" column="BAR" type="integer" />
</dynamic-component>
</class>
</hibernate-mapping>
Code:
@Entity
public class Person {
private Long id;
private String name;
private Map<String, Field> values = new HashMap<String, Field>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@CollectionOfElements(targetElement=Field.class)
@MapKeyClass(String.class)
public Map<String, Field> getValues() {
return values;
}
public void setValues(Map<String, Field> values) {
this.values = values;
}
}
Method update, download all rows from table customfields (i store in this table description of each custom field(column))
This is how i add new property to mappings
update method call addDynamiAttribute method for each customfield.
Code:
private Property addDynamicAttribute(CustomField customField, PersistentClass persistentClass, Component dynamicComponent) {
// Create a new db column specification.
Column column = new Column();
column.setName(customField.getName());
column.setNullable(customField.isNullable());
column.setUnique(customField.isUnique());
int length = customField.getLength();
if (length != CustomField.DEFAULT_DATABASE_LENGTH) {
column.setLength(length);
}
// Add column to table also.
//persistentClass.getTable().addColumn(column);
// Create a simple value that contains the column and will be set to the
// property as information.
//Mappings mappings = dynamicComponent.getMappings();
//mappings.addColumnBinding(customField.getName(), column, persistentClass.getTable());
SimpleValue simpleValue = new SimpleValue(persistentClass.getTable());
simpleValue.addColumn(column);
simpleValue.setTypeName(customField.getTypeClass().getName());
//simpleValue.setTable(persistentClass.getTable());
// Create a new property.
Property property = new Property();
property.setName(customField.getName());
property.setNodeName(customField.getName());
property.setPropertyAccessorName(customField.getPropertyAccessorName());
property.setCascade(customField.getCascade());
property.setValue(simpleValue);
return property;
}
public void update(Session session) {
List<CustomField> customFields = getCustomFields(session);
for (CustomField customField : customFields) {
// The persistent dynamic attribute.
PersistentClass persistentClass = configuration.getClassMapping(customField.getPersistentClass().getName());
Property dynamicProperty = persistentClass.getProperty(customField.getPropertyName());
// Get the dynamic component and
Component dynamicComponent = (Component) dynamicProperty.getValue();
// Add the new attribute if the component is a dynamic component.
if (dynamicComponent.isDynamic()) {
dynamicComponent.addProperty(addDynamicAttribute(customField, persistentClass, dynamicComponent));
//addDynamicAttribute(customField, persistentClass, dynamicComponent);
}
}
printMappings();
new SchemaUpdate(configuration).execute(true, true);
printMappings();
}