У меня есть отношение ManyToMany между двумя таблицами, User и Ключевое слово. Пользователь является владельцем отношений. Если я удалю Пользователь, я удаляю сначала все Ключевые словаПользователь, а затем удаляет Пользователь. Это работает так, как ожидалось.Hibernate: ManyToMany inverse Удалить
Но я не знаю, как удалить слова и автоматически удалять отношения ко всем пользователей.
Вот мой код.
@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
Я гугл и попробовал много разных вещей, но ничего не работает.
Я ценю любую помощь.
Большое спасибо,
Marco
Благодарим вас за подробное объяснение и вашу помощь! В методе removeKeyword мне нужно проверить, имеет ли пользователь ключевое слово: this.keywords.contains (keyword). Для этого contains-check мне нужно перезаписать метод equals ?! Если у меня есть тысячи пользователей, метод contains не слишком медленный? Я думаю, что есть более элегантное решение.;) – devchzh
Просто чтобы быть ясным: я не думаю, что ваше решение не изящно, только то, что я думаю, что я должен делать с методом «содержит», кажется, не изящно. Я думаю, вы знаете лучшее решение, чем мой подход «содержит». ;) – devchzh
Нет, вам не нужно переопределять метод equals. И вам не нужно проверять, содержит ли список ключевое слово: вы * знаете *, он содержит его. Просто удалите его из списка. Мои тесты с Hibernate показывают, что удаление пользователя (владельца) автоматически удалит ассоциацию со всеми его ключевыми словами, но удаление ключевого слова (обратная сторона) автоматически не удалит ассоциацию со всеми его пользователями. Я даже не уверен, что это стандартное поведение. Альтернативой является использование собственного запроса, который удаляется из таблицы соединений. –