title: JPA / Hibernate orphan removal using joining entity
body: <p>First off, I've done a lot of research on this and have not found this example yet, so I'm hoping the answer is not "re-design your database".</p>
  
  <p>Using Spring and JPA (and hibernate) to delete one entity, and have it's references (or "orphans"?) automatically deleted too.</p>
  
  <p>Here is the error:
  <strong>The DELETE statement conflicted with the REFERENCE constraint "FK_ItemContainer_Item". The conflict occurred in database "MyDatabase2", table "dbo.ItemContainer", column 'itemId'.</strong></p>
  
  <p>Here is the scenario:</p>
  
  <pre><code>@Entity
  @Table(name = "Item")
  public class Item implements java.io.Serializable {
  
    private Integer itemId; //Auto Genenerated Unique ID
    private String item; //Item description
    private Set&lt;ItemContainer&gt; itemContainers = new HashSet&lt;ItemContainer&gt;(0); //Set of ItemContainers
  
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "item", orphanRemoval = true)
    public Set&lt;ItemContainer&gt; getItemContainers() {
      return this.itemContainers;
    }
  }
  
  @Entity
  @Table(name = "ItemContainer")
  public class ItemContainer implements java.io.Serializable {
  
    private Integer itemContainerId; //Auto Genenerated Unique ID
    private Item item; //Item link
    private Container container; //Container link
  
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "itemId")
    public Item getItem() {
      return this.item;
    }
  
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "containerId")
    public Container getContainer() {
      return this.container;
    }
  }
  
  @Entity
  @Table(name = "Container")
  public class Container implements java.io.Serializable {
  
    private Integer containerId; //Auto Genenerated Unique ID
    private String container; //description
    private Set&lt;ItemContainer&gt; itemContainers = new HashSet&lt;ItemContainer&gt;(0);
  
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "container", orphanRemoval = true)
    public Set&lt;ItemContainer&gt; getItemContainers() {
      return this.itemContainers;
    }
  }
  </code></pre>
  
  <p><strong>A Container and an Item can both exist exclusivity.</strong> 
  <strong>An ItemContainer can only exist containing references to existing Items and Containers</strong></p>
  
  <p>What I want to do is be able to delete an item, and have it's corresponding ItemContainer rows dropped (using orphan removal). Any Containers should still exist.</p>
  
  <p>Here is how i'm trying to remove an Item:</p>
  
  <pre><code>@Override
  public void delete(Item item) {
    EntityManager em = getEntityManager();
    em.remove(em.contains(item) ? item: em.merge(item));
  }
  </code></pre>
  
  <p>I'm aware that I may have to remove the ItemContainers manually first, however I've been following guides and helps to try and get automatic orphan removal working, and would like to see it through.</p>
  
  <p>Any help is appreciated.</p>
  
  <p>Cheers,<br>
  Steve.</p>
  
  <p><strong>EDIT 1:</strong>
  As JB requested: Here is the relevant code being used.</p>
  
  <p>The request is coming from a jsp to </p>
  
  <pre><code>/deleteItem?itemId=${item.itemId}
  </code></pre>
  
  <p>It may be worth mentioning, I'm attempting to do the same in my jUnit tests (I can post the test code and any relevant classes if need be), however I do not receive the error (it passes without throwing a FK constraint error, but the ItemContainer table still contains a reference to the deleted Item).</p>
  
  <p>Item Controller, Service and Dao Implementation:</p>
  
  <pre><code>@Controller
  public class ItemController {
  
    @Autowired
    private ItemsService itemsService;
  
    @RequestMapping(value = "/deleteItem")
    public String deleteItem(@RequestParam() int itemId) {
  
      itemsService.delete(itemId);
  
      return "redirect:systemSettings/items";
    }
  }
  
  @Service("itemsService")
  public class ItemsService {
  
    @Autowired
    private ItemsDAO itemsDao;
  
    public void delete(int itemId) {
  
      itemsDao.delete(itemsDao.getItem(itemId));
    }
  }
  
  @Repository
  @Transactional
  @Component("itemsDao")
  public class ItemsDAOImpl implements ItemsDAO {
  
    @PersistenceContext
    private EntityManager entityManager;
  
    @Override
    public EntityManager getEntityManager() {
      return entityManager;
    }
  
    @Override
    public void setEntityManager(EntityManager entityManager) {
      this.entityManager = entityManager;
    }
  
    @Override
    public Item getItem(int itemId) {
      String queryString = "SELECT i FROM Item i "
          + "LEFT JOIN FETCH i.itemMachines "
          + "WHERE i.itemId=:itemId";
      Query query = getEntityManager().createQuery(queryString);
      query.setParameter("itemId", itemId);
  
      Item item = (Item) query.getSingleResult();
      System.out.println(item.getItemMachines().size());
  
      return item;
    }
  
    @Override
    public void delete(Item item) {
      EntityManager em = getEntityManager();
      em.remove(em.contains(item) ? item : em.merge(item));
    } 
  }
  </code></pre>
  
  <p>Here is the stack trace:</p>
  
  <pre><code>org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
      at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:189)
      at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:155)
      at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:519)
      at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
      at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
      at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
      at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
      at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
      at com.sun.proxy.$Proxy29.delete(Unknown Source)
      at com.home.myproject.service.ItemsService.delete(ItemsService.java:45)
      at com.home.myproject.service.ItemsService$$FastClassBySpringCGLIB$$788e7765.invoke(&lt;generated&gt;)
      at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
      at com.home.myproject.service.ItemsService$$EnhancerBySpringCGLIB$$296a7299.delete(&lt;generated&gt;)
      at com.home.myproject.controllers.ItemController.deleteItem(ItemController.java:121)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:483)
      at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
      at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
      at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
      at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
      at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
      at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
      at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
      at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
      at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
      at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
      at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:744)
  Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
      at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:129)
      at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
      at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
      at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
      at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:211)
      at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:62)
      at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3400)
      at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3630)
      at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:114)
      at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
      at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
      at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
      at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
      at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
      at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
      at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
      at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
      at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
      at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
      ... 50 more
  Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The DELETE statement conflicted with the REFERENCE constraint "FK_ItemContainer_Item". The conflict occurred in database "MyDatabase2", table "dbo.ItemContainer", column 'itemId'.
      at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(Unknown Source)
      at com.microsoft.sqlserver.jdbc.TDSCommand.execute(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(Unknown Source)
      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(Unknown Source)
      at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
      at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
      at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
      ... 64 more
  </code></pre>
  
  <p>Cheers.<br>
  Steve.</p>
  
  <p><strong>Edit 2:</strong></p>
  
  <p>Found this question <a href="https://stackoverflow.com/questions/17018302/jpa-cascade-remove-orphans">JPA Cascade remove orphans</a> - James' answer confirms what JB is saying, still no idea why it wont work though :(</p>