Announcement Announcement Module
Collapse
No announcement yet.
Using @Valid removes child collections Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using @Valid removes child collections

    I have two different pages where different parts of an object can be added/updated. One main screen where simple information like name etc are specified and another form where a child collection is updated. If I have 2 elements added to the child collection and then go back into the general form and resave the data, it wipes out the child collections here is the code

    Code:
    /*** StoreContoller.java ***/
    @RequestMapping(value = "/store", method = RequestMethod.GET)
    	public String store(@RequestParam(defaultValue="") String storeId, Model model){
    		//updating existing store
    		if(!storeId.equals("")){
    			model.addAttribute("store", storeDao.getStoreById(storeId));
    		}
    		//adding new store
    		else{
    			model.addAttribute("store", new Store());
    		}
    		return "store";
    	}
    
    @RequestMapping(value = "/store", method = RequestMethod.POST)
    	public String storeSubmit(@Valid Store store, BindingResult result){
    		if(!result.hasErrors()){
    			//now save the store
    			log.debug("adding/updating store " + store);
    			storeDao.saveStore(store);
    			return "redirect:/";
    		}
    		log.error("error in binding store", result.toString());
    		return "store";
    	}
    Code:
    /*** StoreDoa */
    public void saveStore(Store store){
    		log.debug("saving store " + store);
    		Session session = sessionFactory.getCurrentSession();
    		session.saveOrUpdate(store);
    		session.flush();
    	}
    Code:
    /**** Store.java */
    @Entity
    @Table(name="clicksvn_stores")
    public class Store implements Serializable {
    @Id
    	private String id = IDGenerator.createId();
    	
    	@NotEmpty
    	private String name;
    	@NotEmpty
    	private String server;
    	
    	@NotEmpty
    	private String username;
    	@NotEmpty
    	private String password;
    	
    	private String schedulingExpression;
    	
    	private boolean scheduled;
    	
    	@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true)
    	@JoinColumn(name="store_id")
    	private Collection<Project> projects = new LinkedHashSet<Project>();
    	
     .....
    }
    Code:
    /**** Project class */
    @Entity
    @Table(name="clicksvn_store_projects")
    public class Project implements Serializable {
    	private static final long serialVersionUID = -276787615885478824L;
    
    	@Id
    	private String id = IDGenerator.createId();
    	
    	private String internalName;
    	private String displayName;
    	
    	@ManyToOne
    	@JoinColumn(name="store_id", insertable=false, updatable=false)
    	private Store store;
    ...
    }
    Any help would be appreciated. I have tried specifying dynamic update as true on Store entity but still doesnt helps.

  • #2
    The problem is you aren't using the model object but a new fresh instance onto which the submitted request parameters are bound.

    Either store the object in the session in between requests (using @SessionAttributes) or create a @ModelAttribute method which retrieves the object from the database on subsequent requests.

    Comment


    • #3
      Originally posted by Marten Deinum View Post
      The problem is you aren't using the model object but a new fresh instance onto which the submitted request parameters are bound.

      Either store the object in the session in between requests (using @SessionAttributes) or create a @ModelAttribute method which retrieves the object from the database on subsequent requests.
      That makes sense. How do i use the model attribute. I tried changing the controller method to

      Code:
      @RequestMapping(value = "/store", method = RequestMethod.POST)
      public String storeSubmit(@Valid @ModelAttribute("store") Store store, BindingResult result){
      but that didnt seemed to help

      Comment


      • #4
        okay I am still a little confused about what is the best way to do this but these are the changes I made and its working fine now. Thanks
        Code:
        //StoreController
        	@ModelAttribute("store")
        	public Model getStore(String storeId, Model model){
        	  if(storeId != null){
        	    Store store = storeDao.getStoreById(storeId);
        	    if(store != null){
        	      model.addAttribute("store", store);
        	    }	    
        	    else{
        	      model.addAttribute("store", new Store());
        	    }	    
        	  }	  
        	  return model;
        	}
        
        @RequestMapping(value = "/store", method = RequestMethod.POST)
        public String storeSubmit(@Valid @ModelAttribute("store") Store store, BindingResult result){
        ...

        Comment


        • #5
          If you have a @ModelAttribute annotated method you don't need to add it to the model, simply return the Store object and it will be added to the model for you. That saves you a couple of lines.

          Code:
          @ModelAttribute("store")
          public Store getStore(String storeId){
            Store store = new Store();
            if (storeId != null) {
              store = storeDao.getStoreById(storeId)
            }
            return store;
          }
          Basically it depends on what you want. THe @ModelAttribute is executed before each request handling method on the controller, advantage is that your application is stateless (nothing is stored in the session). Drawback is the object is retrieved for each request. Storing it in the session overcomes this last drawback but makes your application stateful and storing large amounts of data in the session can become problematic.

          Comment

          Working...
          X