title: Lazy loading of child throwing session error
body: <p>I'm the following error when calling purchaseService.updatePurchase(purchase) inside my TagController:</p>
  
  <pre><code>SEVERE: Servlet.service() for servlet [PurchaseAPIServer] in context with path [/PurchaseAPIServer] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.model.Purchase.tags, no session or session was closed] with root cause
  org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.model.Purchase.tags, no session or session was closed
      at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
      at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
      at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)
      at org.hibernate.collection.PersistentSet.add(PersistentSet.java:212)
      at com.app.model.Purchase.addTags(Purchase.java:207)
      at com.app.controller.TagController.createAll(TagController.java:79)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:212)
      at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
      at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
      at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
      at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
      at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
      at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)
      at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
      at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)
      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
      at java.lang.Thread.run(Thread.java:662)
  </code></pre>
  
  <p><em><strong>TagController:</em></strong></p>
  
  <pre><code>@RequestMapping(value = "purchases/{purchaseId}/tags", method = RequestMethod.POST, params = "manyTags")
  @ResponseStatus(HttpStatus.CREATED)
  public void createAll(@PathVariable("purchaseId") final Long purchaseId, @RequestBody final Tag[] entities)
  {
      Purchase purchase = purchaseService.getById(purchaseId);
  
      Set&lt;Tag&gt; tags = new HashSet&lt;Tag&gt;(Arrays.asList(entities));
  
      purchase.addTags(tags);
      purchaseService.updatePurchase(purchase);
  }
  </code></pre>
  
  <p><br>
  <strong><em>Purchase:</em></strong></p>
  
  <pre><code>@Entity
  @XmlRootElement
  public class Purchase implements Serializable
  {
  
      /**
       * 
       */
      private static final long serialVersionUID = 6603477834338392140L;
  
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
  
      @OneToMany(mappedBy = "purchase", fetch = FetchType.LAZY, cascade={CascadeType.ALL})
      private Set&lt;Tag&gt; tags;
  
      @JsonIgnore
      public Set&lt;Tag&gt; getTags()
      {
          if (tags == null)
          {
              tags = new LinkedHashSet&lt;Tag&gt;();
          }
          return tags;
      }
  
      public void setTags(Set&lt;Tag&gt; tags)
      {
          this.tags = tags;
      }
  
      public void addTag(Tag tag)
      {
          tag.setPurchase(this);
          this.tags.add(tag);
      }
  
      public void addTags(Set&lt;Tag&gt; tags)
      {
          Iterator&lt;Tag&gt; it = tags.iterator();
  
          while (it.hasNext())
          {
              Tag tag = it.next();
              tag.setPurchase(this);
              this.tags.add(tag);
          }
      }
  
      ...
  }
  </code></pre>
  
  <p><br>
  <strong><em>Tag:</em></strong></p>
  
  <pre><code>@Entity
  @XmlRootElement
  public class Tag implements Serializable
  {
      /**
       * 
       */
      private static final long serialVersionUID = 5165922776051697002L;
  
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
  
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumns({@JoinColumn(name = "PURCHASEID", referencedColumnName = "ID")})
      private Purchase purchase;
  
      @JsonIgnore
      public Purchase getPurchase()
      {
          return purchase;
      }
  
      public void setPurchase(Purchase purchase)
      {
          this.purchase = purchase;
      }
  }
  </code></pre>
  
  <p><br>
  <strong><em>PurchaseService:</em></strong></p>
  
  <pre><code>@Service
  public class PurchaseService implements IPurchaseService
  {
      @Autowired
      private IPurchaseDAO purchaseDAO;
  
      public PurchaseService()
      {
  
      }
  
      @Transactional
      public List&lt;Purchase&gt; getAll()
      {
          return purchaseDAO.findAll();
      }
  
      @Transactional
      public Purchase getById(Long id)
      {
          return purchaseDAO.findOne(id);
      }
  
      @Transactional
      public void addPurchase(Purchase purchase)
      {
          purchaseDAO.save(purchase);
      }
  
      @Transactional
      public void updatePurchase(Purchase purchase)
      {
          purchaseDAO.update(purchase);
      }
  }
  </code></pre>
  
  <p><br>
  <strong><em>TagService:</em></strong></p>
  
  <pre><code>@Service
  public class TagService implements ITagService
  {
      @Autowired
      private ITagDAO tagDAO;
  
      public TagService()
      {
  
      }
  
      @Transactional
      public List&lt;Tag&gt; getAll()
      {
          return tagDAO.findAll();
      }
  
      @Transactional
      public Tag getById(Long id)
      {
          return tagDAO.findOne(id);
      }
  
      @Transactional
      public void addTag(Tag tag)
      {
          tagDAO.save(tag);
      }
  
      @Transactional
      public void updateTag(Tag tag)
      {
          tagDAO.update(tag);
      }
  }
  </code></pre>
  
  <p><br>
  Any ideas on how I can fix this? (I want to avoid using EAGER loading).</p>
  
  <p>Do I need to setup some form of session management for transactions?</p>
  
  <p>Thanks</p>
  
  <h2>Updates based on JB suggestions</h2>
  
  <p><em><strong>TagController</em></strong></p>
  
  <pre><code>@RequestMapping(value = "purchases/{purchaseId}/tags", method = RequestMethod.POST, params = "manyTags")
  @ResponseStatus(HttpStatus.CREATED)
  public void createAll(@PathVariable("purchaseId") final Long purchaseId, @RequestBody final Tag[] entities)
  {
      Purchase purchase = purchaseService.getById(purchaseId);
  
      // Validation
      RestPreconditions.checkRequestElementNotNull(purchase);
      RestPreconditions.checkRequestElementIsNumeric(purchaseId);
  
      Set&lt;Tag&gt; tags = new HashSet&lt;Tag&gt;(Arrays.asList(entities));
  
      purchaseService.addTagsToPurchase(purchaseId, tags);
  }
  </code></pre>
  
  <p><em><strong>PurchaseService</em></strong></p>
  
  <pre><code>@Transactional
  public void addTagsToPurchase(Long purchaseId, Set&lt;Tag&gt; tags)
  {
      Purchase p = purchaseDAO.findOne(purchaseId);
  
      p.addTags(tags);
  }
  </code></pre>