2015-08-15 53 views
2

我已經嘗試了一段時間來更新使用Spring Boot + Spring Data JPA的實體。我收到了所有正確的觀點。我的編輯視圖通過ID向我返回正確的實體。一切都很好..直到我真的試圖保存/合併/堅持對象。 單次我回來一個新的實體與一個新的ID。我只是不知道爲什麼。我在網上查了一些例子,以及你可能會提及的重複問題的鏈接。那麼,我在這些代碼中犯了什麼錯誤?彈簧數據JPA合併更新實體

package demo; 

    import javax.persistence.Column; 
    import javax.persistence.Entity; 
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType; 
    import javax.persistence.Id; 
    import javax.persistence.Table; 

    @Entity 
    @Table(name = "ORDERS") 
    public class Order { 

     @Id 
     @GeneratedValue(strategy = GenerationType.AUTO) 
     private Integer id; 

     @Column(name = "ORDER_NAME") 
     private String name; 

     @Column(name = "ORDER_DESCRIPTION") 
     private String description; 

     @Column(name = "ORDER_CONTENT") 
     private String content; 

     public Order() {} 

     public Order(String name, String description, String content) { 
      this.name = name; 
      this.description = description; 
      this.content = content; 
     } 

     public String getContent() { 
      return content; 
     } 

     public String getDescription() { 
      return description; 
     } 

     public String getName() { 
      return name; 
     } 

     public Integer getId() { 
      return this.id; 
     } 

     public void setContent(String content) { 
      this.content = content; 
     } 

     public void setDescription(String description) { 
      this.description = description; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) 
       return true; 
      if (obj == null) 
       return false; 
      if (getClass() != obj.getClass()) 
       return false; 
      Order other = (Order) obj; 
      if (content == null) { 
       if (other.content != null) 
        return false; 
      } else if (!content.equals(other.content)) 
       return false; 
      if (description == null) { 
       if (other.description != null) 
        return false; 
      } else if (!description.equals(other.description)) 
       return false; 
      if (id == null) { 
       if (other.id != null) 
        return false; 
      } else if (!id.equals(other.id)) 
       return false; 
      if (name == null) { 
       if (other.name != null) 
        return false; 
      } else if (!name.equals(other.name)) 
       return false; 
      return true; 
     } 

     @Override 
     public int hashCode() { 
      final int prime = 31; 
      int result = 1; 
      result = prime * result + ((content == null) ? 0 : content.hashCode()); 
      result = prime * result 
        + ((description == null) ? 0 : description.hashCode()); 
      result = prime * result + ((id == null) ? 0 : id.hashCode()); 
      result = prime * result + ((name == null) ? 0 : name.hashCode()); 
      return result; 
     } 

     @Override 
     public String toString() { 
      return "Order [id=" + id + ", name=" + name + ", description=" 
        + description + ", content=" + content + "]"; 
     } 

    } 





    package demo; 

    import org.springframework.data.jpa.repository.JpaRepository; 

    public interface OrderRepository extends JpaRepository<Order, Integer> { 

     public Order findByName(String name); 


    } 

package demo;

import javax.persistence.EntityManager; 
    import javax.persistence.PersistenceContext; 
    import javax.transaction.Transactional; 

    import org.springframework.stereotype.Service; 

    @Service("customJpaService") 
    public class CustomJpaServiceImpl implements CustomJpaService{ 

     @PersistenceContext 
     private EntityManager em; 

     @Transactional 
     public Order saveOrUpdateOrder(Order order) { 

      if (order.getId() == null) { 
       em.persist(order); 
      } else { 
       em.merge(order); 
      } 
      return order; 
     } 

    } 

package demo;

import java.util.List; 

    import org.springframework.beans.factory.annotation.Autowired; 
    import org.springframework.stereotype.Controller; 
    import org.springframework.validation.BindingResult; 
    import org.springframework.web.bind.annotation.ModelAttribute; 
    import org.springframework.web.bind.annotation.PathVariable; 
    import org.springframework.web.bind.annotation.RequestMapping; 
    import org.springframework.web.bind.annotation.RequestMethod; 
    import org.springframework.web.servlet.ModelAndView; 
    import org.springframework.web.servlet.mvc.support.RedirectAttributes; 

    @Controller 
    public class OrderController { 

     //refactor to service with 
     //logging features 
     @Autowired 
     OrderRepository orderRepo; 

     @Autowired 
     CustomJpaService customJpaService; 

     @RequestMapping(value="/orders", method=RequestMethod.GET) 
     public ModelAndView listOrders() { 

      List<Order> orders = orderRepo.findAll(); 

      return new ModelAndView("orders", "orders", orders); 

     } 

     @RequestMapping(value="/orders/{id}", method=RequestMethod.GET) 
     public ModelAndView showOrder(@PathVariable Integer id, Order order) { 
      order = orderRepo.findOne(id); 
      return new ModelAndView("showOrder", "order", order); 
     } 

     @RequestMapping(value="/orders/edit/{id}", method=RequestMethod.GET) 
     public ModelAndView editForm(@PathVariable("id") Integer id) { 
      Order order = orderRepo.findOne(id); 
      return new ModelAndView("editOrder", "order", order); 
     } 

     @RequestMapping(value="/updateorder", method=RequestMethod.POST) 
     public String updateOrder(@ModelAttribute("order") Order order, BindingResult bindingResult, final RedirectAttributes redirectattributes) { 

      if (bindingResult.hasErrors()) { 
       return "redirect:/orders/edit/" + order.getId(); 
      } 

      customJpaService.saveOrUpdateOrder(order); 
      redirectattributes.addFlashAttribute("successAddNewOrderMessage", "Order updated successfully!"); 
      return "redirect:/orders/" + order.getId(); 
     } 


     @RequestMapping(value="/orders/new", method=RequestMethod.GET) 
     public ModelAndView orderForm() { 
      return new ModelAndView("newOrder", "order", new Order()); 
     } 

     @RequestMapping(value="/orders/new", method=RequestMethod.POST) 
     public String addOrder(Order order, final RedirectAttributes redirectAttributes) { 
      orderRepo.save(order); 
      redirectAttributes.addFlashAttribute("successAddNewOrderMessage", "Success! Order " + order.getName() + " added successfully!"); 
      return "redirect:/orders/" + order.getId(); 
     } 

    } 

此代碼後。我的看法返回到正確的URL,但ID爲4 < - 這是一個新的實體。它應該說3與更新的屬性。

+0

那麼我做了一些測試,似乎在更新實體的POST方法中,order對象返回的ID爲null。我不知道爲什麼模型屬性出現在表單中,我使用@ModelAttribute註解。 – DtechNet

回答

2

您需要在GET請求和POST請求之間存儲實體。您的選擇:

  1. 在文章的開頭重新從數據庫中的實體,然後從張貼的實體
  2. 存放在隱藏的表單變量的實體信息
  3. 商店的實體在會議
  4. 複製其屬性

3是唯一正確的解決方案,因爲它允許樂觀的併發控制,並且比隱藏的形式變量更安全。

@SessionAttributes("modelAttributeName")添加到控制器的頂部,並將SessionStatus參數添加到POST處理程序方法中。完成後致電sessionStatus.setComplete()。有關工作示例,請參見Spring MVC: Validation, Post-Redirect-Get, Partial Updates, Optimistic Concurrency, Field Security

+0

你只對API使用「method = RequestMethod.PUT」嗎?因爲我注意到JSP和Spring表單標籤不支持「PUT」。所以我猜你仍然使用POST方法進行「更新」。實際更新發生在數據層。另外,你是否必須在實體上使用@Version? – DtechNet

+0

其實它不是網頁瀏覽器,不會從html表單中刪除/刪除,而不僅僅是彈簧。雖然可以使用put/delete w Ajax。你只需要@version進行樂觀鎖定 –