-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Mapping a one-to-many map
PostPosted: Tue Jan 06, 2004 3:02 am 
Newbie

Joined: Tue Oct 21, 2003 10:47 pm
Posts: 10
I want to model a one-to-many parent-child relationship with a Map, the key being the child's id. So I have the following classes (with xdoclets):
Code:

/**
* @hibernate.class table="simple"
*/
public class Simple
{

    private Long id;
    private Map elements = new HashMap();


    public Simple(){}

    public int hashCode()
    {
        return getId().hashCode();
    }

    public boolean equals(Object object)
    {
        if (! (object instanceof Parent))
            return false;

        return ((Parent)object).getId().equals(getId());
    }


    /**
     * Gets the value of id
     * @return Long
     * @hibernate.id column="id"
     *               generator-class="native"
     *               unsaved-value="null"
     */
    public Long getId()  {
        return this.id;
    }

    /**
     * Sets the value of id
     * @param argId Value to assign to this.id
     */
    public void setId(Long argId) {
        this.id = argId;
    }

    /**
     * Gets the value of elements
     * @return Map
     * @hibernate.map table="parent_child"
     *                cascade="all"
     *                lazy="false"
     *                inverse="true"
     * @hibernate.collection-key column="id"
     * @hibernate.collection-index type="long"
     * @hibernate.collection-one-to-many class="pc.SimpleElement"
     */
    public Map getElements()  {
        return this.elements;
    }

    /**
     * Sets the value of elements
     * @param argElements Value to assign to this.elements
     */
    public void setElements(Map argElements) {
        this.elements = argElements;
    }

    public void addElement(SimpleElement e) {
        e.setParent(this);
        this.elements.put(e.getId(), e);
    }

}

Code:

/**
* @hibernate.class table="simpleelement"
*/
public class SimpleElement
{

    private Long id;
    private String name;

    public SimpleElement(){}



    public int hashCode()
    {
        return getId().hashCode();
    }

    public boolean equals(Object object)
    {
        if (! (object instanceof Parent))
            return false;

        return ((Parent)object).getId().equals(getId());
    }

    /**
     * Gets the value of id
     * @return Long
     * @hibernate.id column="id"
     *               generator-class="native"
     *               unsaved-value="null"
     */
    public Long getId()  {
        return this.id;
    }

    /**
     * Sets the value of id
     * @param argId Value to assign to this.id
     */
    public void setId(Long argId) {
        this.id = argId;
    }


    /**
     * Gets the value of parent
     * @return Simple
     * @hibernate.many-to-one
     */
    public Simple getParent()  {
        return this.parent;
    }

    /**
     * Sets the value of parent
     * @param argParent Value to assign to this.parent
     */
    public void setParent(Simple argParent) {
        this.parent = argParent;
    }

}


This gives me the following mappings:
Code:
<hibernate-mapping>
    <class
        name="pc.Simple"
        table="simple"
        dynamic-update="false"
        dynamic-insert="false"
    >

        <id
            name="id"
            column="id"
            type="java.lang.Long"
            unsaved-value="null"
        >
            <generator class="native">
            </generator>
        </id>

        <map
            name="elements"
            table="parent_child"
            lazy="false"
            sort="unsorted"
            inverse="true"
            cascade="all"
        >

              <key
                  column="id"
              />

              <index
                  column=""
                  type="long"
              />

              <one-to-many
                  class="pc.SimpleElement"
              />
        </map>

    </class>

</hibernate-mapping>

<hibernate-mapping>
    <class
        name="pc.SimpleElement"
        table="simpleelement"
        dynamic-update="false"
        dynamic-insert="false"
    >

        <id
            name="id"
            column="id"
            type="java.lang.Long"
            unsaved-value="null"
        >
            <generator class="native">
            </generator>
        </id>

        <many-to-one
            name="parent"
            class="pc.Simple"
            cascade="none"
            outer-join="auto"
            update="true"
            insert="true"
            column="parent"
        />

    </class>

</hibernate-mapping>



I use the objects as follows:
Code:
        Simple s = new Simple("Parent");
        SimpleElement e1 = new SimpleElement("Test1");
        SimpleElement e2 = new SimpleElement("Test2");
        SimpleElement e3 = new SimpleElement("Test3");

        id = (Long) session.save(s);
        session.save(e1);
        s.addElement(e1);
        session.save(e2);
        s.addElement(e2);
        session.save(e3);
        s.addElement(e3);

        Simple s2 = (Simple)session.load(Simple.class, id);
        Map map = s2.getElements();


However, this always returns a map with 0 elements in it. Inspecting the database shows that the SimpleElements are being created with the correct parent id, and the load is doing a join to get them out, but they're not appearing in the final map. Does anybody know what I might be doing wrong?

Thanks,
Steve


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 06, 2004 11:13 am 
Newbie

Joined: Thu Dec 04, 2003 5:53 am
Posts: 11
Location: Toulouse, France
Two things:

1) you need to flush the session before loading
2) since you set "cascade=all", you don't need to save the individual SimpleElements. They'll automatically get saved when the session is flushed, simply by virtue of having been added to the parent's Map of children.

I think the test code should look more like this:

Code:
Simple s = new Simple("Parent");
SimpleElement e1 = new SimpleElement("Test1");
SimpleElement e2 = new SimpleElement("Test2");
SimpleElement e3 = new SimpleElement("Test3");
s.addElement(e1); 
s.addElement(e2);
s.addElement(e3);
id = (Long) session.save(s);
session.flush();

Simple s2 = (Simple)session.load(Simple.class, id);
Map map = s2.getElements();


You may have to commit after the flush and then create a new session before loading s2, but I'm not sure... no time to test it now.


Top
 Profile  
 
 Post subject: Re: Mapping a one-to-many map
PostPosted: Tue Jan 06, 2004 12:44 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Tarka wrote:
I want to model a one-to-many parent-child relationship with a Map, the key being the child's id.

It's conceptually inconsistent.
Map key is set by the user inserting the key in map, so you cannot use the id column as a PK and as the map index. Use 2 columns and use a proper add() method in Simple to actually use the id as an index.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 08, 2004 2:36 am 
Newbie

Joined: Tue Oct 21, 2003 10:47 pm
Posts: 10
Thanks all, on thinking about this some more I'm probably approaching this the wrong way. I need to go back and look at this again.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.