31

Một câu hỏi Hibernate ...: PHibernate nhiều-nhiều gắn với cùng một thực thể

Sử dụng khuôn khổ Chú thích Hibernate, tôi có một thực thể User. Mỗi User có thể có một bộ sưu tập của bạn bè: một Bộ sưu tập khác của User s. Tuy nhiên, tôi đã không thể tìm ra cách để tạo ra một liên kết nhiều-nhiều trong lớp User bao gồm một danh sách các User s (sử dụng một bảng trung gian của người dùng-bạn bè).

Đây là lớp người dùng và chú thích của nó:

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

Người dùng-friend bảng vẽ bản đồ chỉ có hai cột, cả hai đều là các phím nước ngoài cho uid cột của bảng tbl_users. Hai cột là personId (nên ánh xạ tới người dùng hiện tại) và friendId (chỉ định id của người bạn của người dùng hiện tại).

Vấn đề là trường "bạn bè" tiếp tục bị vô hiệu, mặc dù tôi đã điền trước bảng bạn bè sao cho tất cả người dùng trong hệ thống là bạn bè với tất cả người dùng khác. Tôi thậm chí đã cố gắng chuyển đổi các mối quan hệ để @OneToMany, và nó vẫn đi ra null (mặc dù đầu ra gỡ lỗi Hibernate cho thấy một truy vấn SELECT * FROM tbl_friends WHERE personId = ? AND friendId = ?, nhưng không có gì khác).

Bất kỳ ý tưởng nào về cách điền danh sách này? Cảm ơn bạn!

Trả lời

47

@ManyToMany với bản thân khá khó hiểu vì cách bạn thường mô hình hóa này khác với cách "Hibernate". Vấn đề của bạn là bạn đang thiếu một bộ sưu tập khác.

Hãy suy nghĩ theo cách này - nếu bạn đang lập bản đồ "tác giả"/"sách" thành nhiều người, bạn cần bộ sưu tập "tác giả" trên Bộ sưu tập Sách và "sách" trên Tác giả. Trong trường hợp này, thực thể "Người dùng" của bạn đại diện cho cả hai đầu của một mối quan hệ; do đó bạn cần bộ sưu tập "bạn bè của tôi" và "bạn của":

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

Bạn vẫn có thể sử dụng cùng một bảng kết hợp, nhưng lưu ý rằng các cột tham gia/nghịch đảo được hoán đổi trên bộ sưu tập.

Bộ sưu tập "bạn bè" và "friendOf" có thể hoặc không phù hợp (tùy thuộc vào "tình bạn" của bạn luôn luôn chung) và bạn không phải phơi bày chúng theo cách này trong API của bạn, tất nhiên, nhưng đó là cách để ánh xạ nó trong Hibernate.

+0

Tôi đã hy vọng bạn 'd đến để giải cứu của tôi cho lần thứ ba :) Nó làm việc hoàn hảo, và lời giải thích của bạn xóa lên sự hiểu biết của tôi về ER đáng kể. Cảm ơn bạn rất nhiều lần nữa! :) – Magsol

+1

Tôi có thể kết hợp bạn bè và bạn bè không? Và nếu không, hơn tôi cần giúp đỡ với jsonmanagedreference và jsonbackreference trong một thực thể trong câu hỏi này: http://stackoverflow.com/questions/24563066/hibernate-user-and-friends-jsonreference – dikkini

+0

Tôi đang sử dụng Hibernate 5 và một bộ sưu tập là đủ - bằng cách sử dụng hai tạo hàng trùng lặp trong tbl_friends. – mdziob

0

Trên thực tế nó rất đơn giản và có thể đạt được bằng cách làm theo nói rằng bạn đã sau thực thể

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 cho cùng:

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

Và kiểm tra trường hợp

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

} 
Các vấn đề liên quan