Search code examples
javahibernatejpaormhibernate-mapping

How to map java.util.Map with associations in hibernate xml?


I have entity Person as follows:

@Entity
@Table(name = "Person")
@Inheritance(strategy = InheritanceType.JOINED)
public class Person implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "personName", length = 16, nullable = false)
    private String name;
.....................
}

I have entity Teacher as follows:

@Entity
@Table(name = "teacher")
@PrimaryKeyJoinColumn(name = "PersonId")
public class Teacher extends Person implements Serializable {

    private Map<String, Child> childByName = new HashMap<>();
        ......................................
}

I have entity Child as follows:

@Entity
@Table(name = "CHILD")
@PrimaryKeyJoinColumn(name = "PersonId")
public class Child extends Person implements Serializable {
        ..............................
}

Map Teacher.childByName should map name property of Child entity as a key and Child entity as a value. The relationship between Teacher and Child is one-to-many.

I need this mapping to be in xml format. For now I did this in Person.hbm.xml :

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

<hibernate-mapping>
    <class name="com.masterhibernate.SimpleHibernateDemo.Person"
        table="Person">
        <cache usage="read-write" />

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

        <property name="name">
            <column name="name" length="24" not-null="true" />
        </property>
        <property name="surname">
            <column name="surname" length="36"></column>
        </property>
        <property name="address">
            <column name="address" length="32"></column>
        </property>
        <joined-subclass name="com.masterhibernate.SimpleHibernateDemo.Parent"
            table="Parent">
            <key column="person_id" foreign-key="parent_person" />
            <property name="job" column="WorkPlace" length="22" type="string" />
            <set name="children" inverse="true" cascade="save-update" lazy="true">
                <cache usage="read-write" />
                <!-- specifies foreign key column of child table -->
                <key column="ParentPK" />
                <one-to-many class="com.masterhibernate.SimpleHibernateDemo.Child" />
            </set>
        </joined-subclass>
        <joined-subclass name="com.masterhibernate.SimpleHibernateDemo.Child"
            table="Child">
            <key column="person_id" foreign-key="child_person" />
            <property name="toy" column="toy" length="55" type="string" />
            <many-to-one name="parent"
                class="com.masterhibernate.SimpleHibernateDemo.Parent" column="ParentPK"
                lazy="false" fetch="join" foreign-key="child_parent" />
            <set name="teachers" table="TeacherPupil" inverse="true" lazy="true">
                <key column="child_id" foreign-key="teacherPupil_child" />
                <many-to-many class="com.masterhibernate.SimpleHibernateDemo.Teacher"
                    column="teacher_id" />
            </set>
        </joined-subclass>
        <joined-subclass name="com.masterhibernate.SimpleHibernateDemo.Teacher"
            table="Teacher">
            <key column="person_id" foreign-key="teacher_person" />
            <property name="subject" column="subject" length="25" type="string" />
            <set name="children" table="TeacherPupil" lazy="false" fetch="join">
                <cache usage="read-write" />
                <key column="teacher_id" foreign-key="teacherPupil_teacher" />
                <many-to-many class="com.masterhibernate.SimpleHibernateDemo.Child"
                    column="child_id" />
            </set>
            <map name="childByName" table="Child_By_Name" embed-xml="true">
                <key column="childByName_id" />
                <index column="childName" type="string" />
                <one-to-many class="com.masterhibernate.SimpleHibernateDemo.Child" />
            </map>
        </joined-subclass>
    </class>
</hibernate-mapping>

Unfortunately <map> doesn't even create separate table called Child_By_Name. Instead it creates columns childByName and childName in table Child. This is very strange.

So, how to map my childByName Map to be in separate table to reference Child as its value?


Solution

  • Since you already have a TeacherPupil table you should use it for your Map association too:

    <map name="childByName" table="TeacherPupil" inverse="true">
    
    <key column="teacher_id" not-null="true"/>
    
    <map-key-many-to-many column="name" class="Child"/>
    
    <many-to-many class="Child"/>
    
    </map>