Как удалить объект с отношениями ManyToMany в JPA (и соответствующие строки таблицы соединений)?

Предположим, у меня есть два объекта: группа и пользователь. Каждый пользователь может быть членом многих групп, и каждая группа может иметь много пользователей.

@Entity public class User { @ManyToMany Set groups; //... } @Entity public class Group { @ManyToMany(mappedBy="groups") Set users; //... } 

Теперь я хочу удалить группу (допустим, у нее много членов).

Проблема в том, что когда я вызываю EntityManager.remove () в какой-либо группе, поставщик JPA (в моем случае Hibernate) не удаляет строки из таблицы соединений, а операция удаления не выполняется из-за ограничений внешнего ключа. Вызов remove () для пользователя работает отлично (я думаю, это связано с владением стороной отношений).

Итак, как я могу удалить группу в этом случае?

Единственный способ, которым я мог придумать, – загрузить всех пользователей в группу, а затем для каждого пользователя удалить текущую группу из своих групп и обновить пользователя. Но мне кажется смешным называть update () для каждого пользователя из группы, чтобы удалить эту группу.

  • Собственность на отношение определяется тем, где вы помещаете атрибут «mappedBy» в аннотацию. Объект, который вы помещаете ‘mappedBy’, является тем, который НЕ является владельцем. У обеих сторон нет шансов стать владельцами. Если у вас нет прецедента «удалить пользователя», вы можете просто перенести право собственности на объект Group , так как в настоящее время User является владельцем.
  • С другой стороны, вы об этом не спрашивали, но об одном стоит знать. groups и users не объединены друг с другом. Я имею в виду, что после удаления экземпляра User1 из Group1.users коллекции User1.groups не изменяются автоматически (что для меня довольно неожиданно)
  • В общем, я бы предложил вам решить, кто является владельцем. Пусть говорят, что User является владельцем. Затем при удалении пользователя пользовательская группа отношений будет автоматически обновляться. Но при удалении группы вы должны сами позаботиться об удалении отношения:

 entityManager.remove(group) for (User user : group.users) { user.groups.remove(group); } ... // then merge() and flush() 

Для меня работает следующее. Добавьте следующий метод к сущности, которая не является владельцем отношения (Group)

 @PreRemove private void removeGroupsFromUsers() { for (User u : users) { u.getGroups().remove(this); } } 

Имейте в виду, что для этого необходимо, чтобы у Группы был обновленный список пользователей (который не выполняется автоматически). поэтому каждый раз, когда вы добавляете группу в список групп в пользовательском сущности, вы также должны добавить пользователя в список пользователей в объекте Group.

Я нашел возможное решение, но … Я не знаю, хорошее ли это решение.

 @Entity public class Role extends Identifiable { @ManyToMany(cascade ={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) @JoinTable(name="Role_Permission", [email protected](name="Role_id"), [email protected](name="Permission_id") ) public List getPermissions() { return permissions; } public void setPermissions(List permissions) { this.permissions = permissions; } } @Entity public class Permission extends Identifiable { @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) @JoinTable(name="Role_Permission", [email protected](name="Permission_id"), [email protected](name="Role_id") ) public List getRoles() { return roles; } public void setRoles(List roles) { this.roles = roles; } 

Я пробовал это, и он работает. Когда вы удаляете Роль, также удаляются отношения (но не объекты Permission), а когда вы удаляете Permission, отношения с ролью также удаляются (но не экземпляр Role). Но мы сопоставляем однонаправленное отношение два раза, и оба объекта являются владельцем отношения. Может ли это вызвать некоторые проблемы для спящего режима? Какие проблемы?

Благодаря!

Вышеупомянутый код связан с другим сообщением .

В качестве альтернативы решениям JPA / Hibernate вы можете использовать предложение CASCADE DELETE в определении базы данных вашего ключа fordein в вашей таблице соединений, например (синтаксис Oracle):

 CONSTRAINT fk_to_group FOREIGN KEY (group_id) REFERENCES group (id) ON DELETE CASCADE 

Таким образом, сама СУБД автоматически удаляет строку, указывающую на группу при удалении группы. И работает ли удаление из Hibernate / JPA, JDBC вручную в БД или любым другим способом.

функция удаления каскадов поддерживается всеми основными СУБД (Oracle, MySQL, SQL Server, PostgreSQL).

Для чего это стоит, я использую EclipseLink 2.3.2.v20111125-r10461, и если у меня есть однонаправленное отношение @ManyToMany, я наблюдаю описанную вами проблему. Однако, если я изменю его на двунаправленное отношение @ManyToMany, я могу удалить объект с не-владеющей стороны, и таблица JOIN обновляется соответствующим образом. Это все без использования каких-либо каскадных атрибутов.

Это хорошее решение. Наилучшая часть на стороне SQL – тонкая настройка на любой уровень проста.

Я использовал MySql и MySql Workbench для Cascade для удаления для требуемого внешнего ключа.

 ALTER TABLE schema.joined_table ADD CONSTRAINT UniqueKey FOREIGN KEY (key2) REFERENCES schema.table1 (id) ON DELETE CASCADE; 

Это работает для меня:

 @Transactional public void remove(Integer groupId) { Group group = groupRepository.findOne(groupId); group.getUsers().removeAll(group.getUsers()); // Other business logic groupRepository.delete(group); } 

Кроме того, отметьте метод @Transactional (org.springframework.transaction.annotation.Transactional), это сделает весь процесс за один сеанс, сэкономит некоторое время.

  • Entity Framework Code First - два внешних ключа из одной таблицы
  • Hibernate: MyInterceptor # onFlushDirty никогда не вызывается
  • Разница между FetchType LAZY и EAGER в Java Persistence API?
  • Какую Java ORM вы предпочитаете и почему?
  • В чем разница между fetch = "EAGER" и fetch = "LAZY" в доктрине
  • Можно ли динамически определять имена столбцов в Hibernate / JPA?
  • Как использовать hibernate с MS Access?
  • В чем разница между однонаправленными и двунаправленными ассоциациями JPA и Hibernate?
  • Лучшие бесплатные инструменты ORM для использования с .NET 2.0 / 3.5
  • Ошибка гибернации: org.hibernate.NonUniqueObjectException: другой объект с тем же значением идентификатора уже был связан с сеансом
  • Как вы можете делать пейджинг с NHibernate?
  • Давайте будем гением компьютера.