31

Un'altra domanda Hibernate ...: PHibernate molti-a-molti con la stessa entità

Utilizzando quadro annotazioni di Hibernate, ho un'entità User. Ogni User può avere una raccolta di amici: una raccolta di altri User s. Tuttavia, non sono stato in grado di capire come creare un'associazione Many-to-Many all'interno della classe User che consiste in un elenco di User s (utilizzando una tabella intermedia utente-amici).

Ecco la classe utente e le sue annotazioni:

@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; 
} 

L'utente-amico tabella di mappatura ha solo due colonne, che sono entrambi chiavi esterne alla colonna uid della tabella tbl_users. Le due colonne sono personId (che dovrebbe corrispondere all'utente corrente) e friendId (che specifica l'ID dell'utente corrente dell'utente).

Il problema è che il campo "amici" continua a uscire nullo, anche se ho pre-compilato la tabella amici in modo tale che tutti gli utenti del sistema siano amici di tutti gli altri utenti. Ho anche provato a cambiare la relazione a @OneToMany, e risulta ancora nulla (sebbene l'output di debug di Hibernate mostri una query SELECT * FROM tbl_friends WHERE personId = ? AND friendId = ?, ma nient'altro).

Qualche idea su come compilare questo elenco? Grazie!

risposta

47

@ManyToMany to self è piuttosto confuso perché il modo in cui modificherebbe normalmente questo è diverso dal modo "Hibernate". Il tuo problema è che ti manca un'altra collezione.

Pensa in questo modo: se stai mappando "autore"/"libro" come molti a molti, hai bisogno della raccolta "autori" su Book e della raccolta "libri" su Autore. In questo caso, l'entità "Utente" rappresenta entrambe le estremità di una relazione; quindi è necessario "i miei amici" e "amici di" collezioni:

@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; 

È comunque possibile utilizzare la stessa tabella di associazione, ma si noti che si uniscono/colonne inverseJon vengono scambiati su collezioni.

Le raccolte "friends" e "friendOf" possono o meno corrispondere (a seconda che la tua "amicizia" sia sempre reciproca) e non devi esporle in questo modo nella tua API, ovviamente, ma è il modo di mapparlo in Hibernate.

+0

ti speravo Sono venuto in mio soccorso per la terza volta :) Ha funzionato perfettamente, e la tua spiegazione chiarisce la mia comprensione di ER in modo significativo. Grazie mille ancora una volta! :) – Magsol

+1

Posso combinare amici e amiciDi? E se no, allora ho bisogno di aiuto con jsonmanagedreference e jsonbackreference in una entità in questa domanda: http://stackoverflow.com/questions/24563066/hibernate-user-and-friends-jsonreference – dikkini

+0

Sto usando Hibernate 5 e una collezione è abbastanza: usare due crea righe duplicate in tbl_friends. – mdziob

0

In realtà è molto semplice e potrebbe essere raggiunto seguendo dici avete seguenti entità

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 per lo stesso:

<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> 

E prova caso

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(); 
    } 

} 
Problemi correlati