Hibernate:混合动态(基于地图)和静态(基于Bean)的映射

时间:2010-07-07 14:53:34

标签: hibernate

我正在开发一个存储和管理测试结果的程序。测试具有日期,持续时间和结果等属性。然而,一些测试测量压力,其他测试温度......我希望你能得到这个想法。因此,并非每个测试都具有相同的属性。

我的第一个想法是将测试表中的测试结果提取到单独的结果表中,从而创建1:1的关系。为了保持测试结果的可扩展性,我希望将结果存储在Maps而不是Beans中。

然而,似乎Hibernate不喜欢我的方法。有没有人有这种映射的经验?还有更好的选择吗?


编辑以获取示例和进一步说明

 --------
|  Test  |
|id      |
+--------+
|date    |
|duration| 1       1  ---------- 
|...     | --------- |  Medium  |
 --------            |testID    |
                     +----------+
                     |medium    |
                     |pressure  |
                      ----------

Medium是测试可以拥有的一个属性。由于可以添加其他属性,我不想对Medium类进行硬编码,而是将其映射为Map,存储三个属性。我的想法是,Test会有Map<String, Map<String, Object>>来表示与之相关的所有属性。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hoerbiger.versuchsdb.domain">
 <class name="Test" lazy="false">

  <id name="id">
   <generator class="native"/>
  </id>

  <property name="datum"/>

  <many-to-one name="material" class="Material"/>

  <set name="testgeraete" table="Test_Testgeraet" lazy="false">
   <key column="testID"/>
   <many-to-many column="geraetID" class="Testgeraet"/>
  </set>

  <!-- Here it's getting important -->

  <one-to-one name="medium" entity-name="Medium" constrained="false" lazy="false"
              access="com.hoerbiger.versuchsdb.hibernate.TestAccessor"/>

 </class>
</hibernate-mapping>

com.hoerbiger.versuchsdb.hibernate.TestAccessor是一个PropertyAccessor,用于访问我想用于关系的地图

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hoerbiger.versuchsdb.domain">
 <class entity-name="Medium" lazy="false">

  <id name="id" type="long">
   <generator class="foreign">
    <param name="property">id</param>
   </generator>
  </id>

  <one-to-one name="id" class="Test" constrained="true"/>

  <property name="medium" type="string"/>

  <property name="pressure" type="int"/>

 </class>
</hibernate-mapping>

为了尝试有效的方法,我使用了这个主要方法。请注意最后几行

@SuppressWarnings("unchecked")
public static void main(String[] args) {
    Session s = Helper.getSessionfactory().getCurrentSession();
    s.beginTransaction();
    //Change to dynamic session
    s = s.getSession(EntityMode.MAP);

    Map<String, Object> test = (Map<String, Object>) s.createQuery("from Test").iterate().next();
    //for me, prints "25"
    System.out.println(test.get("id"));

    Map<String, Object> medium = new HashMap<String, Object>();
    medium.put("id", test);
    medium.put("medium", "Luft");
    medium.put("pressure", 40);

    s.save("Medium", medium);
    s.getTransaction().commit();
    System.out.println("---");
    s = Helper.getSessionfactory().getCurrentSession();
    s.beginTransaction();

    Test t = (Test) s.createQuery("from Test").iterate().next();
    //for me, prints "null, 2010-07-07 00:00:00.0" (Test.toString())
    System.out.println(t);
    //"25"
    System.out.println(t.getId());
    //"{medium={id=null, 2010-07-07 00:00:00.0, ...}}"
    System.out.println(t.getProperties());
    //"true"
    System.out.println(t.getProperties().get("medium").get("id") == t);

    //This is really weird - hibernate loads the map with a Test stored, but when
    //saving, it expects a Long. With this line, the Commit succeeds
    t.getProperties().get("medium").put("id", t.getId());
    s.getTransaction().commit();
}

这些最后一行有什么用?这是休眠或配置错误的错误吗?

1 个答案:

答案 0 :(得分:1)

经过多次阅读后,我找出了我的错误:目前,我的媒体映射看起来像这样:

<hibernate-mapping package="com.hoerbiger.versuchsdb.domain"> 
 <class entity-name="Medium" lazy="false"> 

  <id name="id" type="long"> 
   <generator class="foreign"> 
    <param name="property">id</param> 
   </generator> 
  </id> 

  <one-to-one name="id" class="Test" constrained="true"/> 

  <property name="medium" type="string"/> 

  <property name="pressure" type="int"/> 

 </class> 
</hibernate-mapping>

但它应该是这样的:

<hibernate-mapping package="com.hoerbiger.versuchsdb.domain"> 
 <class entity-name="Medium" lazy="false"> 

  <id name="id" type="long"> 
   <generator class="foreign"> 
    <param name="property">test</param> 
   </generator> 
  </id> 

  <one-to-one name="test" class="Test" constrained="true"/> 

  <property name="medium" type="string"/> 

  <property name="pressure" type="int"/> 

 </class> 
</hibernate-mapping>

问题是在生成器中使用“id”和一对一约束

Hibernate使用两个属性来表示主键一对一约束,在我的例子中:

  • id是PK&amp; FK,即test.getId(),Long
  • test是对自己的外来对象的引用

由于Map不是类型安全的,您可以通过Test覆盖首先存储的Long。两个值都只是读入同一个映射条目。通过将两次出现的id更改为test,引用具有自己的条目,并且不再覆盖id值