Подтвердить что ты не робот

Hibernate соединение "многие-ко-многим" с одним и тем же объектом

Другой вопрос спящего режима...: P

Используя структуру аннотаций Hibernate, у меня есть объект User. Каждый User может иметь коллекцию друзей: Коллекция других User s. Однако мне не удалось выяснить, как создать ассоциацию Many-to-Many в классе User, состоящую из списка User (используя промежуточную таблицу друзей пользователя).

Здесь класс пользователя и его аннотации:

@Entity
@Table(name="tbl_users")
public class User {

    @Id
    @GeneratedValue
    @Column(name="uid")
    private Integer uid;

    ...

    @ManyToMany(
            cascade={CascadeType.PERSIST, CascadeType.MERGE},
            targetEntity=org.beans.User.class
    )
    @JoinTable(
            name="tbl_friends",
            [email protected](name="personId"),
            [email protected](name="friendId")
    )
    private List<User> friends;
}

Таблица сопоставления пользователя-друга имеет только два столбца, оба из которых являются внешними ключами столбца uid таблицы tbl_users. Два столбца: personId (которые должны отображаться для текущего пользователя) и friendId (который указывает идентификатор текущего пользователя).

Проблема заключается в том, что поле "друзья" продолжает выдаваться нулевым, даже если я предварительно заполнил таблицу друзей, чтобы все пользователи в системе были друзьями со всеми другими пользователями. Я даже попытался переключить отношение на @OneToMany, и он по-прежнему выходит нулевым (хотя вывод отладки Hibernate показывает запрос SELECT * FROM tbl_friends WHERE personId = ? AND friendId = ?, но больше ничего).

Любые идеи о том, как заполнить этот список? Спасибо!

4b9b3361

Ответ 1

@ManyToMany для себя довольно запутанно, потому что способ, которым вы обычно моделируете это, отличается от способа "Hibernate". Ваша проблема в том, что вам не хватает другой коллекции.

Подумайте об этом так: если вы сопоставляете "автор" / "книгу" как много-ко-многим, вам нужна коллекция "авторов" в книге "Книга" и "книги" на Авторе. В этом случае ваш объект "Пользователь" представляет оба конца отношений; поэтому вам нужны "мои друзья" и "друг" коллекций:

@ManyToMany
@JoinTable(name="tbl_friends",
 [email protected](name="personId"),
 [email protected](name="friendId")
)
private List<User> friends;

@ManyToMany
@JoinTable(name="tbl_friends",
 [email protected](name="friendId"),
 [email protected](name="personId")
)
private List<User> friendOf;

Вы все равно можете использовать одну и ту же таблицу связей, но обратите внимание, что столбцы join/inverseJon меняются местами в коллекциях.

Коллекции "друзья" и "friendOf" могут соответствовать или не совпадать (в зависимости от того, всегда ли ваша "дружба" всегда взаимна), и вам не нужно раскрывать их таким образом в вашем API, конечно, но что способ сопоставить его в Hibernate.

Ответ 2

На самом деле это очень просто и может быть достигнуто следующим образом: у вас есть следующая сущность

public class Human {
    int id;
    short age;
    String name;
    List<Human> relatives;



    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public short getAge() {
        return age;
    }
    public void setAge(short age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Human> getRelatives() {
        return relatives;
    }
    public void setRelatives(List<Human> relatives) {
        this.relatives = relatives;
    }

    public void addRelative(Human relative){
        if(relatives == null)
            relatives = new ArrayList<Human>();
        relatives.add(relative);
    }




}

HBM для этого:

<hibernate-mapping>
    <class name="org.know.july31.hb.Human" table="Human">
        <id name="id" type="java.lang.Integer">
            <column name="H_ID" />
            <generator class="increment" />
        </id>
        <property name="age" type="short">
            <column name="age" />
        </property>
        <property name="name" type="string">
            <column name="NAME" length="200"/>
        </property>
        <list name="relatives" table="relatives" cascade="all">
         <key column="H_ID"/>
         <index column="U_ID"/>
         <many-to-many class="org.know.july31.hb.Human" column="relation"/>
      </list>
    </class>
</hibernate-mapping>

И тестовый пример

import org.junit.Test;
import org.know.common.HBUtil;
import org.know.july31.hb.Human;

public class SimpleTest {

    @Test
    public void test() {
        Human h1 = new Human();
        short s = 23;
        h1.setAge(s);
        h1.setName("Ratnesh Kumar singh");
        Human h2 = new Human();
        h2.setAge(s);
        h2.setName("Praveen Kumar singh");
        h1.addRelative(h2);
        Human h3 = new Human();
        h3.setAge(s);
        h3.setName("Sumit Kumar singh");
        h2.addRelative(h3);
        Human dk = new Human();
        dk.setAge(s);
        dk.setName("D Kumar singh");
        h3.addRelative(dk);
        HBUtil.getSessionFactory().getCurrentSession().beginTransaction();
        HBUtil.getSessionFactory().getCurrentSession().save(h1);
        HBUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
        HBUtil.getSessionFactory().getCurrentSession().beginTransaction();
        h1 = (Human)HBUtil.getSessionFactory().getCurrentSession().load(Human.class, 1);
        System.out.println(h1.getRelatives().get(0).getName());

        HBUtil.shutdown();
    }

}