title: Hibernate saveorupdate or merge for saving/updating one-to-many relationship objects
body: <p>I am developing an application using Spring MVC 3 and Hibernate. I have 2 classes User and TenancyDetails with parent-child relationship. In the edit details functionality, we can edit the details of class User and dynamically add classTenancyDetails items and save the changes. I am using hibernate saveorupdate() method for this and hibernate is creating a new record for class User when it should be updating the existing record. Here is my code.</p>
  
  <p>Model classes: </p>
  
  <pre><code>@Entity
  @Table(name="tenancydetails")
  public class TenancyDetails {
  
  @Column(name="tenancyID")
  @Id 
  @GeneratedValue
  private int tenancyId;  
  
  @Column(name="landlordName")
  @NotNull
  private String landlordName;
  
  @Column(name="landLordEmail") 
  @NotNull
  private String landlordEmail;
  
  @Column(name="fromDate") 
  @NotNull
  private Date fromDate;
  
  @Column(name="toDate")
  @NotNull
  private Date toDate;
  
  @Column(name="location") 
  @NotNull
  private String location;
  
  @ManyToOne(cascade=CascadeType.ALL)
  @JoinColumn(name="userId", nullable=false)
  private User user;
  
  @Transient 
  protected Object[] jdoDetachedState; 
  
  public User getUser() {
      return user;
  }
  
  public void setUser(User user) {
      this.user = user;
  }
  
  public int getTenancyId() {
      return tenancyId;
  }
  
  public void setTenancyId(int tenancyId) {
      this.tenancyId = tenancyId;
  }
  
  public String getLandlordName() {
      return landlordName;
  }
  
  public void setLandlordName(String landlordName) {
      this.landlordName = landlordName;
  }
  
  public String getLandlordEmail() {
      return landlordEmail;
  }
  
  public void setLandlordEmail(String landlordEmail) {
      this.landlordEmail = landlordEmail;
  }
  
  public Date getFromDate() {
      return fromDate;
  }
  
  public void setFromDate(Date fromDate) {
      this.fromDate = fromDate;
  }
  
  public Date getToDate() {
      return toDate;
  }
  
  public void setToDate(Date toDate) {
      this.toDate = toDate;
  }
  
  public String getLocation() {
      return location;
  }
  
  public void setLocation(String location) {
      this.location = location;
  }       
  }
  
  @Entity
  @Table(name="User")
  public class User {
  @Column(name="userId")
  @Id     
  private int userId; 
  
  @Column(name="name")
  private String name;
  
  @Column(name="emailId")
  @NotEmpty(message = "Please enter your email id")
  @Size(max = 50, message = "Email id can only be upto 50 characters long")
  private String emailId;
  
  @Column(name="password")
  @NotEmpty(message = "Please enter your password")
  @Size(max = 20, message = "Password can only be upto 20 characters long")
  private String password;    
  
  @OneToMany(cascade={CascadeType.ALL}, fetch = FetchType.EAGER)
  @Cascade({org.hibernate.annotations.CascadeType.DELETE_ORPHAN,
      org.hibernate.annotations.CascadeType.PERSIST,
      org.hibernate.annotations.CascadeType.SAVE_UPDATE})
  @JoinColumn(name="userId"/*, nullable=true*/)
  @LazyCollection(LazyCollectionOption.FALSE)
  private List&lt;TenancyDetails&gt; tenancyDetails = null;
  
  public User(){
      tenancyDetails = new AutoPopulatingList&lt;TenancyDetails&gt;(TenancyDetails.class);
  }
  
  public List&lt;TenancyDetails&gt; getTenancyDetails() {
      return tenancyDetails;
  }
  
  public void addTenancyDetail(TenancyDetails tenancyDetail) {
      if (!tenancyDetails.contains(tenancyDetail)) {
          tenancyDetails.add(tenancyDetail);
      }
  }
  
  public void setTenancyDetails(List&lt;TenancyDetails&gt; tenancyDetails) {
      this.tenancyDetails = tenancyDetails;
  }
  
  public int getUserId() {
      return userId;
  }
  
  public void setUserId(int userId) {
      this.userId = userId;
  }
  
  public String getName() {
      return name;
  }
  
  public void setName(String name) {
      this.name = name;
  }
  
  public String getEmailId() {
      return emailId;
  }
  
  public void setEmailId(String emailId) {
      this.emailId = emailId;
  }
  
  public String getPassword() {
      return password;
  }
  
  public void setPassword(String password) {
      this.password = password;
  }   
  
  }
  </code></pre>
  
  <p>Controller:</p>
  
  <pre><code>@RequestMapping(value = "/Profile/{userId}",  method = RequestMethod.POST)
      public ModelAndView saveProfileDetails(@PathVariable int userId, Model model, HttpServletRequest request, HttpServletResponse response,
              HttpSession session, ModelMap modelMap, @ModelAttribute("user") User user) {            
          System.out.println("am in save");
          model.addAttribute("user", user);
          System.out.println(user.getPassword());
          System.out.println(user.getTenancyDetails().get(0).getUser().getUserId());
          System.out.println(model.containsAttribute("user"));        
          tenantRatingService.saveProfileDetails(user);
          return new ModelAndView("editProfile","user", user);
      }
  </code></pre>
  
  <p>DAO method:</p>
  
  <pre><code>public void saveProfileDetails(User user){      
          System.out.println("inside the save profile method");
          Session session = getSession();
          Transaction transaction = session.beginTransaction();
          System.out.println("before save: " + user.getPassword());
          System.out.println("before save: " + user.getTenancyDetails().get(0).getUser().getUserId());        
          session.saveOrUpdate(user);
          transaction.commit();
          session.flush();
          System.out.println(user.getPassword());
      }
  </code></pre>
  
  <p>I have also set the id fields of both classes as AUTO_INCREMENT fields in mysql. 
  Is there a problem with the one to many mapping or the @GeneratedValue I have used? Or is it to do with the saveorupdate() method? Should I use merge() in this case? Just before the saveorupdate() statement, the value of the existing userId is printed out correctly!</p>
  
  <p>Can someone please let me know where I am going wrong? Thanks in advance.</p>