简体   繁体   English

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

[英]How to persist dynamic extension property in Hibernate?

I am facing a complex requirement, puzzling me a lot. 我面临着一个复杂的要求,这让我很困惑。 Help... 救命...

Hibernate:4.3.6 MySql 5.6.21 休眠:4.3.6 MySql 5.6.21

For support dynamic extension on standard product, such as: Standard POJO: 为了支持对标准产品的动态扩展,例如:标准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; } } 

So, ExtProperity's type is Map<String, Map<String, Object>> , it will be used for storage extension property. 因此,ExtProperity的类型为Map<String, Map<String, Object>> ,它将用于存储扩展属性。 Then we need to persist it to database. 然后,我们需要将其持久保存到数据库中。

Here is my hbm.xml: 这是我的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> 

Test code: 测试代码:

 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(); 

The configuraion in hbm.xml cannot work. hbm.xml中的配置无法正常工作。 Please help me. 请帮我。 Thanks. 谢谢。

 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) 

Table structure of GSPPerson is: GSPPerson的表结构为:

ID      Age    
1       30     

Table structure of GSPPerson_ext is: 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 and Ext2 are extension columns, so we defined a Hashmap<String,HashMap<String,Object> to storage the extension columns. Ext1和Ext2是扩展列,因此我们定义了Hashmap<String,HashMap<String,Object>来存储扩展列。 We hope persist the Hashmap to extension columns. 我们希望将Hashmap保留到扩展列。

You're defining a property ext1 on a HashMap , which it doesn't have, so Hibernate will look for those properties. 您正在HashMap上定义属性ext1 ,但它没有,因此Hibernate将查找这些属性。 What does ext1 mean anyways? ext1到底是什么意思?

Additionally, you're putting Object into the map, which Hibernate would not be able to map. 此外,您要将Object放入地图中,而Hibernate无法将其映射。

I'm not sure about what extensions are in your case or what the key of that nested map does represent, but I'd probably model extensions as separate entities. 我不确定您使用的是什么扩展,也不知道嵌套映射的键代表什么,但是我可能会将扩展建模为单独的实体。 Something like that: 像这样:

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
}

And in your Person class: 在您的Person类中:

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

As you can see I'd map the extension value to String and not Object in order to allow Hibernate to map that value correctly. 如您所见,我将扩展值映射到String而不是Object ,以允许Hibernate正确映射该值。 Most types (at least primitives) can be converted to and from strings anyways so that would not be a problem. 无论如何,大多数类型(至少是原语)都可以在字符串之间来回转换,所以这不是问题。 If the values get more complex you'd either need an appropriate string mapping (eg JSON or XML), serialize the values to byte arrays or make the values custom entities. 如果值变得更复杂,则需要适当的字符串映射(例如JSON或XML),将值序列化为字节数组或使值成为自定义实体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM