2013-05-29 163 views
1

我有兩個表之間的ManyToMany關係,用戶關鍵字。用戶是關係的所有者。如果我刪除用戶,我先刪除所有關鍵字從此用戶然後刪除用戶。這按預期工作。休眠:ManyToMany反刪除

但我不知道如何刪除關鍵字並自動刪除關係到所有用戶

這是我的代碼到目前爲止。

 

    @Entity 
    @Table(name = "user") 

    public class User { 

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

     @Column(name = "name") 
     private String name; 

     @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
     @Fetch(value = FetchMode.SUBSELECT) 
     @JoinTable(name = "user_has_keyword", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "keyword_id")) 
     private List keywords = new ArrayList(); 

     // Getters and setters 
     ... 
    } 

 

    @Entity 
    @Table(name = "keyword") 
    public class Keyword { 

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

     @Column(name = "keyword") 
     private String keyword; 

     @ManyToMany(mappedBy = "keywords") 
     private List users = new ArrayList(); 

     // Getters and setters 
     ... 
    } 

 

    @Service("myService") 
    @Transactional("transactionManager") 
    public class MyService { 

     @Resource(name = "sessionFactory") 
     private SessionFactory sessionFactory; 

     @SuppressWarnings("unchecked") 
     public List getAllUsers() { 
     Session session = this.sessionFactory.getCurrentSession(); 

     Query query = session.createQuery("FROM User"); 

     return query.list(); 
     } 

     public User getUser(Integer id) { 
     Session session = this.sessionFactory.getCurrentSession(); 
     return (User) session.get(User.class, id); 
     } 

     public void addUser(User user) { 
     Session session = this.sessionFactory.getCurrentSession(); 
     session.save(user); 
     } 

     public void deleteUser(User user) { 
     Session session = this.sessionFactory.getCurrentSession(); 

     // 1st, delete relations 
     user.getKeywords().clear(); 
     session.update(user); 

     // 2nd, delete User object 
     session.delete(user); 
     } 

     public Keyword getKeyword(Integer id) { 
     Session session = this.sessionFactory.getCurrentSession(); 
     return (Keyword) session.get(Keyword.class, id); 
     } 

     public Keyword addKeyword(Keyword keyword) { 
     Session session = this.sessionFactory.getCurrentSession(); 
     session.save(keyword); 

     return keyword; 
     } 

     public void deleteKeyword(Keyword keyword) { 
     Session session = this.sessionFactory.getCurrentSession(); 

     // 1st, delete relations 
     keyword.getUsers().clear(); 
     session.update(keyword); 

     // 2nd, delete User object 
     keyword = getKeyword(keyword.getId()); 
     session.delete(keyword); 
     } 
    } 

 

    @Controller 
    public class MyController { 

     @Resource(name = "myService") 
     private MyService myService; 

     @RequestMapping(value = "/add", method = RequestMethod.GET) 
     public String add(Model model) { 

     Keyword k = new Keyword(); 
     k.setKeyword("yellow"); 
     k = myService.addKeyword(k); 

     User u1 = new User(); 
     u1.setName("Bart"); 
     u1.getKeywords().add(k); 
     myService.addUser(u1); 

     User u2 = new User(); 
     u2.setName("Lisa"); 
     u2.getKeywords().add(k); 
     myService.addUser(u2); 

     return "/"; 
     } 

     @RequestMapping(value = "/delete/user", method = RequestMethod.GET) 
     public String deleteUser(Model model) { 

     User u = myService.getUser(1); 
     myService.deleteUser(u); 

     return "/"; 
     } 

     @RequestMapping(value = "/delete/keyword", method = RequestMethod.GET) 
     public String deleteKeyword(Model model) { 

     Keyword k = myService.getKeyword(1); 
     myService.deleteKeyword(k); 

     return "/"; 
     } 

    } 

如果我瀏覽到/刪除/關鍵字我得到以下異常:

 

    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.blabla.prototype.Keyword.users, no session or session was closed 

我一派,並嘗試了很多不同的東西,但沒有用。

我很感激任何幫助。

非常感謝你,

馬爾科

回答

1

的LazyInitializationException中沒有任何與刪除。您正在加載控制器中的關鍵字。這使服務加載關鍵字,而不用初始化其懶惰的用戶列表。然後將該關鍵字返回給控制器,並提交事務,並關閉會話,使關鍵字脫離會話。

然後,您將此分離的關鍵字傳遞給該服務以將其刪除。該服務因此收到分離的關鍵字,並嘗試訪問其用戶列表。由於關鍵字已分離且用戶列表尚未加載,因此會導致LazyInitializationException。

服務方法應該將關鍵字的ID作爲參數刪除,加載它,從而使用附加的關鍵字,然後繼續刪除。

現在要回答你的問題,你已經明白了刪除用戶的權利:刪除用戶的所有關鍵字以刪除,因爲用戶是關聯的所有者。刪除關鍵字時,應用相同的邏輯:從所有用戶引用它刪除關鍵字,並刪除關鍵字:附帶單位工作時

public void deleteKeyword(Integer id) { 
    Keyword keyword = getKeyword(id); 
    for (User user : keyword.getUsers()) { 
     user.removeKeyword(keyword); 
    } 
    session.delete(keyword); 
} 

注意,您不必調用update()。附加實體的狀態會自動並透明地保存到數據庫中。

+0

非常感謝您的詳細解釋和您的幫助!在removeKeyword方法中,我需要檢查用戶是否擁有關鍵字:this.keywords.contains(keyword)。對於這個包含檢查,我需要覆蓋equals方法?!如果我有成千上萬的用戶,包含方法是不是太慢?我想有一個更優雅的解決方案。;) – devchzh

+0

只是要清楚:我不認爲,你的解決方案並不高雅,正如我在想我與「包含」方法有關似乎不是優雅。我想,你知道比我的「包含」方法更好的解決方案。 ;) – devchzh

+0

不,您不必重寫equals方法。而且您不必檢查列表是否包含關鍵字:*您知道*它包含它。只需從列表中刪除它。我對Hibernate的測試表明,刪除用戶(所有者方)將自動刪除與其所有關鍵字的關聯,但刪除關鍵字(反面)不會自動刪除與其所有用戶的關聯。我甚至不確定這是標準行爲。另一種方法是使用從連接表中刪除的本地查詢。 –