views:

61

answers:

2

Hi I’m trying to map some classes in hibernate there and have general problem how such mapping can be done. There is User class and Facebook user class which has the following structure User Class :

public class User{
 public User(){}
 Long Id;
 String FirstName;
 String LastName;
 ....
 FbUser fbuser;
 //// all requred 
 getters and setters...
}

Facebook class FbUser can have list of Friends which are objects of the same class FbUser.

public class FbUser{
 public FbUser(){}
 Long fbId;
 String FirstName;
 String LastName;
 List<FbUser> friends;
 //// all requred 
 getters and setters...
}

Till now I made many to one relation between User And FbUser.

<hibernate-mapping>
    <class
        name="User"
        table="User"
    >

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

        <property
            name="FirstName"
            update="true"
            insert="true"
            not-null="false"
            unique="false"
            type="java.lang.String"
        >
            <column name="FirstName" />
        </property>
 <property
            name="LastName"
            update="true"
            insert="true"
            not-null="false"
            unique="false"
            type="java.lang.String"
        >
            <column name="LastName" />
        </property>
        <many-to-one
            name="fbUser"
            class="FbUser"
            cascade="all"
            column="fbId"
            unique="true" 
        />

    </class>
</hibernate-mapping>

And now the FbUser Mapping:

<hibernate-mapping>
    <class
        name="FbUser"
        table="FbUser"
    >

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

        <property
            name="FirstName"
            update="true"
            insert="true"
            not-null="false"
            unique="false"
            type="java.lang.String"
        >
            <column name="FirstName" />
        </property>

        <property
            name="LastName"
            type="java.lang.String"
            update="true"
            insert="true"
            column="LastName"
            not-null="true"
            unique="false"
        />
    </class>
</hibernate-mapping>

Chow can I map FbUser List inside the FbUser Map file? I got lost :(

+2  A: 

Well, first: User has a one-to-one relation with FbUser, correct? second: Map FbUser to FbUser as a many to many relation using a list or a set. I have an Set example here:

    <set 
        name="friends"
        table="FbUser" <!-You may use other table here if you want->
        access="field">
        <key 
            column="fbId"/>
        <many-to-many 
            class="bla.bla.bla.FbUser"
            column="friend_id" />
    </set>
Plínio Pantaleão
+2  A: 

You can create an additional class named, for instance, MyFriends

public class FbUser {

    List<MyFriends> friends = new ArrayList<MyFriends>();

}

Just relevant part

If you have a index-column

<hibernate-mapping>
    <class name="FbUser">
        <list name="myFriends">
            <key column="ME_ID" insert="false" update="false"/>
            <list-index column="WHICH COLUMN SHOULD BE USED AS INDEX"/>
            <one-to-many class="MyFriends"/>
        </list>
    </class>
</hibernate-mapping>

If you do not have a index-column

re-write your list as

public class FbUser {

    Collection<MyFriends> friends = new ArrayList<MyFriends>();

}

And

<hibernate-mapping>
    <class name="FbUser">
        <bag name="columns">
            <key column="ME_ID" insert="false" update="false"/>
            <one-to-many class="MyFriends"/>
        </bag>
    </class>
</hibernate-mapping>

And your MyFriends mapping. Notice you need a composite primary key (implemented as a static inner class)

<class name="MyFriends">
    <composite-id name="myFriendsId" class="MyFriends$MyFriendsId">
        <key-property name="meId"/>
        <key-property name="myFriendId"/>
    </composite-id>
    <many-to-one name="me" class="FbUser" insert="false" update="false"/>
    <many-to-one name="myFriend" class="FbUser" insert="false" update="false"/>
</class>

Your MyFriends is shown as follows

public class MyFriends {

    private MyFriendsId myFrinedId;

    private FbUser me;
    private FbUser myFriend;

    public static class MyFriendsId implements Serializable {

        private Integer meId;
        private Integer myFriendId;

        // getter's and setter's

        public MyFriendsId() {}
        public MyFriendsId(Integer meId, Integer myFriendId) {
            this.meId = meId;
            this.myFriendId = myFriendId;
        }

        // getter's and setter's

        public boolean equals(Object o) {
            if(!(o instanceof MyFriendsId))
                return false;

            MyFriendsId other = (MyFriendsId) o;
            return new EqualsBuilder()
                       .append(getMeId(), other.getMeId())
                       .append(getMyFriendId(), other.getMyFriendId())
                       .isEquals();
        }

        public int hashcode() {
            return new HashCodeBuilder()
                       .append(getMeId())
                       .append(getMyFriendId())
                       .hashCode();
        }
    }
}
Arthur Ronald F D Garcia
Hi, Your solution is fascinating. However could you please exlpain why should I use collection instead List if I don't have Index row? and why do I need composite primary key?
danny.lesnik
@danny.lesnik If you use a List, Hibernate will complain you do not have an index column. See here why: http://stackoverflow.com/questions/3580686/hibernate-one-to-many-mapping-works-with-a-list-but-not-a-set/3580835#3580835 You need a composite primary key because your ManyToMany relationship "has been splitted" into a OneToMany relationship. When a ManyToMany relationship is splitted into a OneToMany, **you need a composite primary key**. ManyToMany is similar To OneToMany(with a composite primary key)
Arthur Ronald F D Garcia
@danny.lesnik Keep in mind the solution provided by @Plinio Pantaleão also works fine. But he uses a set. Prefer to use a bag instead **if you does not have a consistent equals and hashCode method** Otherwise, you can get unexpected behavior.
Arthur Ronald F D Garcia
@danny.lesnik Just a correction: ManyToMany is similar to OneToMany-ManyToOne FbUser has **OneToMany** relationship with MyFriend (Collection<MyFriend>) and MyFriend has a **ManyToOne** relationship with FbUser. And when you split a ManyToMany into OneToMany-ManyToOne the joined class (MyFriend) has a composite primary key. See here another example http://stackoverflow.com/questions/1212058/how-to-make-a-composite-primary-key-java-persistence-annotation/1252317#1252317
Arthur Ronald F D Garcia
Hi, may be you can help me with this topic? http://stackoverflow.com/questions/3845772/mapping-same-class-relation-continuation. this is implementation of your suggestion.
danny.lesnik