title: updating value in junction table is troublesome spring data JPA
body: <p>I have two Entities one as </p>
  
  <pre><code>@Entity    
  public class Job {  
  
      @Id
      @GeneratedValue
      private Integer id;
  
      @Size(min = 5,max = 50, message = "Valid title is 5-50 chars")
      private String title;       
  
      @ManyToMany(cascade = {CascadeType.MERGE})
      @JoinTable(name = "jobs_categories",
                  joinColumns = @JoinColumn(name = "jobs_id"),
                  inverseJoinColumns = @JoinColumn(name = "categories_id"))
      private List&lt;Category&gt; categories;
      // omitting setters/getters
  }
  </code></pre>
  
  <p>and other as </p>
  
  <pre><code>@Entity
  public class Category {    
  
      @Id
      @GeneratedValue
      private Integer id;
  
      @Size(min = 5,max = 15, message = "Valid name is 5-15 chars")
      private String name;
  
      @ManyToMany(mappedBy = "categories", cascade = {CascadeType.MERGE}) 
      private List&lt;Job&gt; jobs; 
      // omitting setters/getters
      }
  </code></pre>
  
  <p>I want to implement <strong>CRUD</strong> operations on those two, 
  I save one job with some categories as </p>
  
  <pre><code>Job title - Fullstack JavaScript CSS3 / HTML5 / Developer
  Categories - AngularJS, Backbone.js, CSS, CSS3, Graphic design, HTML, HTML5,
               JavaScript, MongoDB Node.js, twitter bootstrap, Web design.
  </code></pre>
  
  <p>then if I want to update the job by adding or removing categories from above saved Job, it is never updating (e.g, adding/removing) categories. </p>
  
  <p>for updating Job I have method in JobService as</p>
  
  <pre><code>@Service
  public class JobService{
  
      @Autowired
      private JobRepository jobRepository;
  
      @Autowired
      private CategoryRepository categoryRepository;
  
      @Autowired
      private LocalContainerEntityManagerFactoryBean entityManagerFactory;
  
      private Session session;
  
      Logger logger = LoggerFactory.getLogger(JobService.class);      
  
      public void updateJobCategory(Job job) {                
      EntityManager entityManager = entityManagerFactory.getObject().createEntityManager();
      session= entityManager.unwrap(org.hibernate.Session.class);
      logger.info("got Job ID as  ==&gt; " + String.valueOf(job.getId()));
      Job jobObj = (Job) session.get(Job.class, job.getId());
      jobObj.getCategories().clear();     
      logger.info("got Job ID as  ==&gt; " + String.valueOf(jobObj.getId()));
  
      if (!job.getCategories().isEmpty()) {
          logger.info("got job.getCategories() as not Null");
          List&lt;Category&gt; categories = job.getCategories();
          for (Category category : categories) {              
              logger.info("Good job.getCategories() to update ==&gt; " + category.getName());
          }
          logger.info("adding job.getCategories() to update ==&gt; ");
          jobObj.setCategories(job.getCategories());      
  
      }else {
          logger.info("got job.getCategories() as Null");
      }
      session.update(jobObj); 
  
      }
      public void update(Job job) {
          jobRepository.update(job.getId(), job.getTitle());
          updateJobCategory(job);
      }
  }
  </code></pre>
  
  <p>I get log </p>
  
  <pre><code>logger.info("Got job.getCategories() to update" + category.getName());
  </code></pre>
  
  <p>I'm getting updated (new added/old removed) list of all categories, </p>
  
  <pre><code>Hibernate: update job set title=? where id=?
  INFO : com.rhcloud.jobsnetwork.service.JobService - got Job ID as  ==&gt; 1
  Hibernate: select job0_.id as id1_1_0_, job0_.title as title7_1_0_ from job job0_ where job0_.id=?
  Hibernate: select categories0_.jobs_id as jobs_id1_1_0_, categories0_.categories_id as categori2_2_0_, category1_.id as id1_0_1_, category1_.name as name2_0_1_ from jobs_categories categories0_ inner join category category1_ on categories0_.categories_id=category1_.id where categories0_.jobs_id=?
  INFO : com.rhcloud.jobsnetwork.service.JobService - got Job ID as  ==&gt; 1
  INFO : com.rhcloud.jobsnetwork.service.JobService - got job.getCategories() as not Null
  INFO : com.rhcloud.jobsnetwork.service.JobService - Good job.getCategories() to update ==&gt; iOS App Dev
  INFO : com.rhcloud.jobsnetwork.service.JobService - Good job.getCategories() to update ==&gt; Android App Dev
  INFO : com.rhcloud.jobsnetwork.service.JobService - adding job.getCategories() to update
  </code></pre>
  
  <p>but when I see details of Job I get the categories listed which were added on the creation of job not updated ones, I guess it is not updating categories id values in  junction table <code>jobs_categories</code>.
  No idea of Updating categories related to job?</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>When I use </p>
  
  <pre><code>public void persistJob(Job newJob) {
           em.persist(newJob);
         }
  
         public void saveJob(Job job) {
            em.merge(job);
         }
         public void persistCategory(Category newcat) {
           em.persist(newcat);
         }
  </code></pre>
  
  <p>without <code>@Transactional</code> at every method I get expception</p>
  
  <pre><code>javax.persistence.TransactionRequiredException: No transactional EntityManager available
      at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:275)
      at com.sun.proxy.$Proxy167.persist(Unknown Source)
      at com.rhcloud.jobsnetwork.service.JobService.persistJob(JobService.java:29)
      at com.rhcloud.jobsnetwork.service.JobService$$FastClassBySpringCGLIB$$53974ce3.invoke(&lt;generated&gt;)
      at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:649)
      at com.rhcloud.jobsnetwork.service.JobService$$EnhancerBySpringCGLIB$$c08e8d16.persistJob(&lt;generated&gt;)
      at com.rhcloud.jobsnetwork.controllers.JobController.addJobDetail(JobController.java:86)
      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:497)
      at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
      at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
      at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
      at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
      at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
      at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
      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:505)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
      at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
      at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
      at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
      at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:745)
  </code></pre>
  
  <p>After adding <code>@Transactional</code> it works got rid of above exception, I save new job using </p>
  
  <pre><code>@RequestMapping(value = "/add-job", method = RequestMethod.POST)
      public String addJobDetail(@ModelAttribute("job") Job job) {            
          jobService.persistJob(job); 
          return "redirect:/";
      } 
  </code></pre>
  
  <p>I get all the things working perfect, but when I use <code>saveJob</code> in JobController as </p>
  
  <pre><code>@RequestMapping(value = "/updated", method = RequestMethod.POST)
      public String updateJob(@ModelAttribute("job") Job job) {           
          jobService.saveJob(job);
          return "redirect:/";
      } 
  </code></pre>
  
  <p>there is no any category(no earlier added no updated ones) saved in updated job, any suggestions in this case.</p>
  
  <h2>Update - 2</h2>
  
  <p>As per your suggestion I added logger to </p>
  
  <pre><code> @Transactional
     public void saveJob(Job job) {
         logger.error("got job.getCategories() of " + job.getCategories().size());
        em.merge(job);         
     }
  </code></pre>
  
  <p>at this point I get NullPointerException at </p>
  
  <pre><code> logger.error("got job.getCategories() of " + job.getCategories().size() + " size");
  </code></pre>
  
  <p>log/trace is </p>
  
  <pre><code>java.lang.NullPointerException
      at com.rhcloud.jobsnetwork.service.JobService.saveJob(JobService.java:37)
      at com.rhcloud.jobsnetwork.service.JobService$$FastClassBySpringCGLIB$$53974ce3.invoke(&lt;generated&gt;)
      at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
      at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
      at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
      at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
      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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
      at com.rhcloud.jobsnetwork.service.JobService$$EnhancerBySpringCGLIB$$41dc2ac2.saveJob(&lt;generated&gt;)
      at com.rhcloud.jobsnetwork.controllers.JobController.updateJob(JobController.java:109)
      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:497)
      at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
      at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
      at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
      at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
      at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
      at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
      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:505)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
      at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
      at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
      at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
      at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:745)
  </code></pre>