2013-03-15 59 views
1

記錄我有一個問題,需要你的幫助來解決這個問題。我們希望,這胎面可能成爲類似問題的參考...休眠(4.1.2)和春季(3.1.2) - 多對多關係並不存儲在JoinTable

在我最小化的商業模式有用戶和標題。標題應該首先創建,並可以分配給許多用戶,用戶可以共享相同的標題。因此,我創建了兩個名爲User和Title的實體,並具有@ManyToMany關係,並決定Title應擁有此關係。另外,我有一個UnitTest來運行這個例子。

用戶實體

public class User { 

    Long id; 
    String name; 
    Set<Title> titles = new HashSet<Title>(); 

    @Id 
    @GeneratedValue 
    @Column(name = "id")  
    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    @Column(name = "name") 
    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 

    /*============ Approach1 ============*/ 
// @ManyToMany(mappedBy = "users") 
    /*============ Approach2 ============*/ 
// @ManyToMany 
    /*============ Approach3 ============*/ 
    @ManyToMany 
    @JoinTable(name = "tb_title_user", 
       joinColumns = @JoinColumn(name = "user_id"), 
       inverseJoinColumns = @JoinColumn(name = "title_id")) 
    public Set<Title> getTitles() { 
     return titles; 
    } 
    public void setTitles(Set<Title> titles) { 
     this.titles = titles; 
    } 

} 

標題實體

public class Title { 

    Long id; 
    String description; 
    Set<User> users = new HashSet<User>(); 


    @Id 
    @GeneratedValue 
    @Column(name = "id")  
    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    @Column(name = "description") 
    public String getDescription() { 
     return description; 
    } 
    public void setDescription(String description) { 
     this.description = description; 
    } 

    /*============ Approach1 & Approach2 & Approach3 ============*/ 
    @ManyToMany 
    @JoinTable(name = "tb_title_user", 
       joinColumns = @JoinColumn(name = "title_id"), 
       inverseJoinColumns = @JoinColumn(name = "user_id")) 
    public Set<User> getUsers() { 
     return users; 
    } 
    public void setUsers(Set<User> users) { 
     this.users = users; 
    } 
} 

單元測試

public class UserTest { 

    @Autowired 
    private SessionFactory sessionFactory; 


    @Test 
    @Rollback(false) 
    @Transactional 
    public void saveUser(){ 
     Session session = sessionFactory.getCurrentSession(); 
     String now = new Date().toString(); 

     Title title = new Title(); 
     title.setDescription("TitleDescription: " + now); 
     session.save(title); 

     User user = new User(); 
     user.setName("UserName: " + now); 
     user.getTitles().add(title); 

     session.saveOrUpdate(user); 
    } 

} 

如果你看一下聯合在上面,你會看到三種不同的方法。下面,說明如果數據正確地存儲在數據庫中的表:

   Title  User  JoinTable 
Approach1 Yes  Yes  No 
Approach2 Yes  Yes  Yes 
Approach3 Yes  Yes  Yes 

這裏是我的關於每種方法的想法:

Approach1

與Hibernate文檔(http://docs.jboss.org/hibernate/core/4.1/manual/en-US/html/ch07.html#d5e5537)根據我應該遵循Approach1。特別的,因爲文件明確提到:

「正如前面所看到的,對方沒有(不能)描述 物理映射:包含所有者 側屬性名稱綁定一個簡單的mappedBy參數兩個「。

如果我理解正確,我不必在用戶實體中添加@JoinTable。

Approach2

它的工作原理,但它忽略了我的@JoinTable定義和創建其所謂的自己的表:tb_user_tb_title。它聞起來很腥。

Approach3

它的工作原理,但文件說,要不要使用它。所以,在我看來,我可能會後悔在企業產品中使用這種方法。

+0

我覺得你:它會更新該關聯表的關係值)時被忽略錯過關係,根據你的描述[標題應該首先被創建,並且可以被分配給許多用戶,並且用戶可以共享相同的標題],它應該是oneToMany?!! – 2013-03-15 18:37:28

+0

嗨艾哈邁德,這是一個ManyToMany關係,「用戶可能共享相同的標題」。另外,在這個例子中,我不需要任何級聯。我會說「應該首先創建標題」與我的業務工作流程相關,並且可以被視爲業務規則。因此,我確實看到了任何定義差距。感謝您的詢問。 – Rafa 2013-03-15 18:44:07

+0

問題是什麼?正如你發現的那樣,文檔說你必須使用mappedBy,並且不能在反面指定映射。 – 2013-03-15 19:17:53

回答

4

的唯一正確途徑是第一個:

@ManyToMany(mappedBy = "users") 
public Set<Title> getTitles() { 
    return titles; 
} 

... 

@ManyToMany 
@JoinTable(name = "tb_title_user", 
      joinColumns = @JoinColumn(name = "title_id"), 
      inverseJoinColumns = @JoinColumn(name = "user_id")) 
public Set<User> getUsers() { 
    return users; 
} 

反側使用mappedBy屬性的說:「我是反方去看看在目標實體users屬性怎麼看該關聯被映射。「

你在做什麼錯的是你只修改反側測試。JPA /休眠只考慮了業主方知道是否存在關聯。因此,而不是做

user.getTitles().add(title); 

你應該做

title.getUsers().add(user); 

,甚至更好,兩者都做,以確保對象圖是一致的。

我真的希望這胎成爲類似ISSU參考ES,但我對此表示懷疑,因爲我已經回答了這個問題一個極大的時間,它會持續一次又一次,儘管它在文件中明確解釋:

如果協會是雙向的,一方有權作爲所有者,一方必須是反面的結果(即,

[遵循與雙向多對一namy每個關聯方適當的註解爲例]

+0

太棒了!非常感謝JB Nizet的詳細解釋。它在這個例子中運行得非常好,在我的真實情況下(我只是用這個例子來在最小化的場景中重現問題)。希望如果這個問題再次出現,我也可以幫助其他人。 乾杯。 – Rafa 2013-03-18 17:44:05

+0

它也不適用於我,直到我將級聯放入用戶:'@ManyToMany(cascade = CascadeType.ALL)' – Abbas 2013-10-30 17:08:01