views:

397

answers:

3

I have a class User. A user can be a friend with many other users. The relationship is mutual. If A is a friend of B then B is a friend of A. Also I want every relation to store additional data - for example the date when two users became friends. So this is a many-to-many relationship on the same table with additional columns. I know that a middle class Friendship should be created(containing two user ids and column for the date). But I am coming short at mapping this with Hibernate. The thing that stops me is that the mapping is to the same table. I can solve it, if the many-to-many relationship was between two different tables.

+1  A: 

I'm not sure this will fit your case, but give it a try.

@Entity
public class Friend {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int friendId;

    @Column
    private String name;

    @ManyToMany(mappedBy="owner")
    private List<Friendship> friendships;
}

@Entity
public class Friendship {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int friendshipId;

    @OneToOne
    private Friend owner;

    @OneToOne
    private Friend target;

   // other info
}
Bozho
+3  A: 

You have said

many-to-many relationship on the same table

It is not a good idea. It is a nightmare to maintain.

Try this one instead

@Entity
public class Friend {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer friendId;

    @Column
    private String name;

    @OneToMany(mappedBy="me")
    private List<MyFriends> myFriends;

}

@Entity
public class MyFriends {

    @EmbeddedId
    private MyFriendsId id;

    @Column
    private String additionalColumn;

    @ManyToOne
    @JoinColumn(name="ME_ID", insertable=false, updateable=false)
    private Friend me;

    @ManyToOne
    @JoinColumn(name="MY_FRIEND_ID", insertable=false, updateable=false)
    private Friend myFriend;

    @Embeddable
    public static class MyFriendsId implements Serializable {

        @Column(name="ME_ID", nullable=false, updateable=false)
        private Integer meId;

        @Column(name="MY_FRIEND_ID", nullable=false, updateable=false)
        private Integer myFriendId;

        public boolean equals(Object o) {
            if(o == null)
                return false;

            if(!(o instanceof MyFriendsId))
                return false;

            MyFriendsId other = (MyFriendsId) o;
            if(!(other.getMeId().equals(getMeId()))
                return false;

            if(!(other.getMyFriendId().equals(getMyFriendId()))
                return false;

            return true;
        }

        public int hashcode() {
            // hashcode impl
        }

    }


}

regards,

Arthur Ronald F D Garcia
Thanks for your answer. But I have a question. Why is "insertable = false" put in the @ManyToOne relationships? If I remove it then it works. Otherwise the MyFriends is not persisted properly. I am not a Hibernate expert so probably I don't understand something.
Petar Minchev
Ok got it, I haven't used an EmbeddedId like you but just another id column. You have put the insertable=false because the EmbeddedId takes care of it. Your answer is accepted:)
Petar Minchev
You have noticed why. When two properties share the same column, it is a good idea to put settings about it in just one property. Otherwise, Hibernate will complain some errors.
Arthur Ronald F D Garcia
A: 

I had the same problem. You can try something like this:

<class name="Friend" entity-name="RelatedFriend" table="FRIENDS">
    <id name="id" type="long">
        <generator class="native" />
    </id>

    <!-- *** -->

    <set name="relatedFriends" table="RELATED_FRIENDS">
        <key column="FRIEND_ID" />
        <many-to-many column="RELATED_FRIEND_ID" class="Friend" entity-name="RelatedFriend"/>
    </set>
</class>
Bo

related questions