Удаление члена из коллекции ManyToMany вызывает org.h2.jdbc.JdbcBatchUpdateException - PullRequest
1 голос
/ 31 октября 2010
public class Group{
@ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL, mappedBy="groups")
 public Set<User> getUsers() {
  if(users == null)
   return new HashSet<User>();
  else 
   return users;
 }
 public void setUsers(Set<User> users) {
  this.users = users;
 }
}

public class User{

 public void setGroups(Set<Group> groups) {
  this.groups = groups;
 }
    @ManyToMany(cascade = CascadeType.ALL)
 public Set<Group> getGroups() {
  return groups;
 }
}

Теперь, если я удаляю пользователя, он должен автоматически удаляться из всех групп, в которых он был. В любом случае, это то, чего я ожидаю.

Вместо этого я получаю это уродливое исключение:

> Exception in thread "main"
> org.springframework.dao.DataIntegrityViolationException:
> Could not execute JDBC batch update;
> SQL [delete from USERS where ID=?];
> constraint ["FKB4DD17BD8FCA5D9E:
> PUBLIC.GROUPS_USERS FOREIGN
> KEY(USERS_ID) REFERENCES
> PUBLIC.USERS(ID)"; SQL statement:
> delete from USERS where ID=?
> [23003-143]]; nested exception is
> org.hibernate.exception.ConstraintViolationException:
> Could not execute JDBC batch update
>  at
> org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:637)
>  at
> org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:97)
>  at
> org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:471)
>  at
> org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
>  at
> org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
>  at
> org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
> 2010-10-31 19:41:19.044
> java[28733:903] An uncaught exception
> was raised  at
> org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
>  at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
>  at
> org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
>  at $Proxy22.removeUser(Unknown
> Source)  at
> com.stone.gym.controller.UserController.removeUser(UserController.java:43)
>  at
> com.stone.gym.view.UserView$3.handleEvent(UserView.java:121)
>  at
> org.eclipse.swt.widgets.EventTable.sendEvent(Unknown
> Source)  at
> org.eclipse.swt.widgets.Display.sendEvent(Unknown
> Source)  at
> org.eclipse.swt.widgets.Widget.sendEvent(Unknown
> Source)  at
> org.eclipse.swt.widgets.Widget.sendEvent(Unknown
> Source)  at
> org.eclipse.swt.widgets.Widget.sendEvent(Unknown
> Source)  at
> org.eclipse.swt.widgets.Widget.notifyListeners(Unknown
> Source)  at
> org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown
> Source)  at
> org.eclipse.swt.widgets.Display.readAndDispatch(Unknown
> Source)  at
> com.stone.gym.controller.FrontController.run(FrontController.java:30)
>  at
> com.stone.gym.StoneGym.main(StoneGym.java:21)
> 2010-10-31 19:41:19.045
> java[28733:903] Java exception
> occurred Caused by:
> org.hibernate.exception.ConstraintViolationException:
> Could not execute JDBC batch update
>  at
> org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
>  at
> org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
>  at
> org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:254)
>  at
> org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
>  at
> org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
>  at
> org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
>  at
> org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
>  at
> org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1001)
>  at
> org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:339)
>  at
> org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
>  at
> org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
>  at
> org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
>  ... 19 more Caused by:
> org.h2.jdbc.JdbcBatchUpdateException:
> Referential integrity constraint
> violation: "FKB4DD17BD8FCA5D9E:
> PUBLIC.GROUPS_USERS FOREIGN
> KEY(USERS_ID) REFERENCES
> PUBLIC.USERS(ID)"; SQL statement:
> delete from USERS where ID=?
> [23003-143]  at
> org.h2.jdbc.JdbcPreparedStatement.executeBatch(JdbcPreparedStatement.java:1101)
>  at
> org.apache.commons.dbcp.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:231)
>  at
> org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
>  at
> org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:247)
>  ... 28 more

Ответы [ 3 ]

3 голосов
/ 01 ноября 2010

Теперь, если я удаляю пользователя, он должен автоматически удаляться из всех групп, в которых он был. В любом случае, это то, чего я ожидаю.

Я подозреваю, что вы не обновляете "обе стороны ссылки" между User и Group правильно перед удалением данного User, следовательно, исключение нарушения ограничения на уровне таблицы соединений. Примерно так:

for (Group group : user.getGroups()) {
     group.getUsers().remove(user);
}
em.remove(user);

Кроме того, мне интересно, почему вы каскадируете ВСЕ операции (хотите удалить группы при удалении пользователя?)

0 голосов
/ 14 июня 2013

Вы можете использовать эту технику, описанную на сайте Hibernate (http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping-association). Обязательно удалите mappedBy из @ ManyToMany в сущности группы.

 public class Group{
 @ManyToMany(fetch=FetchType.EAGER)
 @JoinTable(name = "groups_users",
        joinColumns = @JoinColumn(name = "groups_id"),
        inverseJoinColumns = @JoinColumn(name = "users_id"))
 public Set<User> getUsers() {
  if(users == null)
   return new HashSet<User>();
  else 
   return users;
 }
 public void setUsers(Set<User> users) {
  this.users = users;
 }
}

public class User{

 public void setGroups(Set<Group> groups) {
  this.groups = groups;
 }
 @ManyToMany
 @JoinTable(name = "groups_users",
        joinColumns = @JoinColumn(name = "users_id"),
        inverseJoinColumns = @JoinColumn(name = "groups_id"))
 public Set<Group> getGroups() {
  return groups;
 }
}
0 голосов
/ 04 ноября 2010

Вам нужно установить для группы значение, равное true, и удалить пользователя, удалит относительное отношение.Однако, если у вас есть пользовательский каскад, группа также будет удалена.Поэтому измените его на save-update.

Предложение Паскаля - лучший способ.Удалить связь явно предпочтительнее всегда.

...