如何在Hibernate中保持动态扩展属性?

时间:2014-11-14 10:09:15

标签: java hibernate

我面临着复杂的要求,让我很困惑。帮助...

休眠:4.3.6 MySql 5.6.21

支持标准产品的动态扩展,例如: 标准POJO:

package com.inspur.gsp;

import java.util.HashMap;
import java.util.Map;

public class Person {
	private String id;
	private String age;

	private Map<CustomPK, Person_T> i18nProperty = new HashMap<CustomPK, Person_T>();

	private Map<String, HashMap<String, Object>> extProperty = new HashMap<String, HashMap<String, Object>>();

	public Map<CustomPK, Person_T> getI18nProperty() {
		return i18nProperty;
	}

	public void setI18nProperity(Map<CustomPK, Person_T> i18nProperty) {
		this.i18nProperty = i18nProperty;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public Map<String, HashMap<String, Object>> getExtProperty() {
		return extProperty;
	}

	public void setExtProperty(Map<String, HashMap<String, Object>> extProperty) {
		this.extProperty = extProperty;
	}
}

因此,ExtProperity的类型为Map<String, Map<String, Object>>,它将用于存储扩展属性。然后我们需要将它持久化到数据库。

这是我的hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Nov 3, 2014 11:48:31 AM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
	<class name="com.inspur.gsp.Person" table="GSPPerson">
		<id name="id" type="java.lang.String">
			<column name="ID" length="36" />
			<generator class="assigned" />
		</id>
		<property name="age" type="java.lang.String">
			<column name="age" length="128" />
		</property>
		<map name="i18nProperty" table="GSPPerson_T">
			<key column="ID"></key>
			<composite-map-key class="com.inspur.gsp.CustomPK">
				<key-property name="culture"></key-property>
			</composite-map-key>
			<composite-element class="com.inspur.gsp.Person_T">
				<property name="description" column="description"></property>
				<property name="comments" column="comments"></property>
			</composite-element>
		</map>

		<map name="extProperty" table="GSPPerson_Ext">
			<key column="ID"></key>
			<map-key type="string" column="ID" />
			<composite-element class="java.util.HashMap">
				<property name="ext1" column="ext1"></property>
				<property name="ext2" column="ext2"></property>
			</composite-element>
		</map>

	</class>
</hibernate-mapping>

测试代码:

SessionFactory sf = createSessionFactory();
		Person person = new Person();
		person.setId("1");
		person.setAge("30");
		HashMap<CustomPK, Person_T> i18nProperity = new HashMap<CustomPK, Person_T>();
		Person_T t1 = new Person_T();
		t1.setComments("abc");
		t1.setDescription("description");
		
		Person_T t2 = new Person_T();
		t2.setComments("efg");
		t2.setDescription("ooooooo");
		
		i18nProperity.put(new CustomPK("1", "cn"), t1);
		i18nProperity.put(new CustomPK("1", "en"), t2);
		person.setI18nProperity(i18nProperity);
		
		HashMap<String, HashMap<String,Object>> extProperty = new HashMap<String, HashMap<String,Object>>();
		HashMap<String,Object> e1 = new HashMap<String,Object>();
		e1.put("ext1", 1);
		e1.put("ext2", "c001");
		
		extProperty.put("1", e1);//1 is person's id ,e1 is extension property.
		person.setExtProperty(extProperty);

		Session session = sf.getCurrentSession();
		Transaction ts = session.beginTransaction();
		session.save(person);
		Person person2 = (Person) session.get(Person.class, "1");

		ts.commit();

hbm.xml中的配置无法正常工作。请帮我。感谢。

INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
Exception in thread "main" org.hibernate.PropertyNotFoundException: field [ext1] not found on java.util.HashMap
	at org.hibernate.property.DirectPropertyAccessor.getField(DirectPropertyAccessor.java:166)
	at org.hibernate.property.DirectPropertyAccessor.getField(DirectPropertyAccessor.java:173)
	at org.hibernate.property.DirectPropertyAccessor.getField(DirectPropertyAccessor.java:158)
	at org.hibernate.property.DirectPropertyAccessor.getGetter(DirectPropertyAccessor.java:181)
	at org.hibernate.internal.util.ReflectHelper.getter(ReflectHelper.java:254)
	at org.hibernate.internal.util.ReflectHelper.reflectedPropertyClass(ReflectHelper.java:230)
	at org.hibernate.mapping.SimpleValue.setTypeUsingReflection(SimpleValue.java:362)
	at org.hibernate.cfg.HbmBinder.createProperty(HbmBinder.java:2350)
	at org.hibernate.cfg.HbmBinder.bindComponent(HbmBinder.java:2037)
	at org.hibernate.cfg.HbmBinder.bindComposite(HbmBinder.java:1836)
	at org.hibernate.cfg.HbmBinder.bindCollectionSecondPass(HbmBinder.java:2634)
	at org.hibernate.cfg.HbmBinder.bindMapSecondPass(HbmBinder.java:2468)
	at org.hibernate.cfg.HbmBinder$MapSecondPass.secondPass(HbmBinder.java:2843)
	at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70)
	at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1695)
	at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1424)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
	at I18nTest.createSessionFactory(I18nTest.java:84)
	at I18nTest.main(I18nTest.java:37)

GSPPerson的表结构是:

ID      Age    
1       30     

GSPPerson_ext的表结构是:

ID   ext1    ext2
1    1       c001

HashMap<String, HashMap<String,Object>> extProperty = new HashMap<String, HashMap<String,Object>>();
        HashMap<String,Object> e1 = new HashMap<String,Object>();
        e1.put("ext1", 1);
        e1.put("ext2", "c001");

        extProperty.put("1", e1);//1 is person's,e1 is extension property.
        person.setExtProperty(extProperty);

Ext1和Ext2是扩展列,因此我们定义了Hashmap<String,HashMap<String,Object>来存储扩展列。我们希望将Hashmap保留为扩展列。

1 个答案:

答案 0 :(得分:0)

您在ext1上定义了一个属性HashMap,它没有,所以Hibernate会查找这些属性。 ext1到底意味着什么?

此外,您将Object放入地图中,Hibernate将无法映射该地图。

我不确定您的案例中的扩展名或嵌套地图的键代表什么,但我可能会将扩展名作为单独的实体进行建模。这样的事情:

class Extension {
  String key;
  Type type; //Type could be an Enum, String, a Number etc. whatever fits your needs
  String value; //use a text representation of the values and convert according to the type
}

在你的Person课程中:

Map<String, Extension> extensions = ...;

正如您所看到的,我将扩展值映射到String而不是Object,以便让Hibernate正确映射该值。大多数类型(至少是基元)无论如何都可以转换为字符串和从字符串转换,这样就不会有问题。如果值变得更复杂,您需要适当的字符串映射(例如JSON或XML),将值序列化为字节数组或将值设置为自定义实体。