2010-08-31 1 views
1

Мы используем сущности-сущности JPA в качестве нашей модели для Spring MVC-контроллера на странице jsp. Одна из наших страниц jsp - это частичный вид этого объекта, который не отображает все свойства. Всякий раз, когда мы пытаемся обновить нашу сущность, используя уровень сервиса с контроллера, свойства, используемые в форме jsp, сохраняются, а все остальные удаляются. Каков правильный способ справиться с этой ситуацией? Мы не хотим указывать скрытые поля в форме.Как сохранить определенные свойства атрибута модели сущности JPA с страницы JSP

Так что в этом случае, когда контроллер вызывает метод service.update (client), поле имени будет пустым, поскольку оно не существует в form.jsp.

form.jsp

<form:form modelAttribute="client" method="get" action="${action}"> 
<table width="100%"> 
    <tr> 
     <td> 
      <table> 
       <tr> 
        <td valign="top"><spring:message code="label.tradeOrderManagementSystem"/>:</td> 
        <td> 
         <form:select path="tradeOrderManagementSystems" > 
          <form:options items="${tradeOrderManagementSystemList}" itemValue="id" itemLabel="name" /> 
         </form:select> 
         <a href="<spring:url value="/tradeOrderManagementSystem/add"/>" class="addAndReturn"><span><spring:message code="add"/></span></a> 
        </td> 
        <td> 
         <form:errors path="tradeOrderManagementSystems" cssClass="errors" /> 
        </td> 
       </tr> 
       <tr><td></td><td>&nbsp;</td></tr> 
      </table> 
     </td> 
    </tr> 
</table> 
<input type="hidden" name="submitted" value="true"> 

Контроллер

@RequestMapping("/{id}/edit") 
public ModelAndView edit(HttpServletRequest request, 
     HttpServletResponse response, 
     @ModelAttribute("client") Client client, 
     BindingResult result, 
     @PathVariable("id") int id, 
     Model model) { 
    ControllerContext ctx = new ControllerContext(request, response); 
    init(ctx); 

    setAdvancedSearchAvailable(ctx, true); 
    buildShowAndEditVerticalMenu(ctx, id, false); 

    if (id == 0) { 
     result.addError(new ObjectError("client", getMessage("error.idNeeded"))); 
     return getModelAndView(ctx, "itEfficiencies/form"); 
    } else { 
     if (!isSubmission(ctx)) { 
      client = clientService.find(id); 
      model.addAttribute("client", client); 
      fillClientForm(model); 
      return getModelAndView(ctx, "itEfficiencies/form"); 
     } else { 
      //clientValidator.validate(client, result); 
      if (result.hasErrors()) { 
       fillClientForm(model); 
       return getModelAndView(ctx, "itEfficiencies/form"); 
      } else { 
       try { 
        //checkClientProperties(client); 
        client.setId(id); 
        client = clientService.update(client); //method updates only form fields and nulls out all others 
       } catch (Exception e) { 
        e.printStackTrace(); 
        result.addError(new ObjectError("client", getMessage("error.save"))); 
        fillClientForm(model); 
        return getModelAndView(ctx, "itEfficiencies/form"); 
       } 
       return getModelAndView(ctx, "/staffingByClient/" + client.getId() + "/show", true); 
      } 
     } 
    } 
}  

Client.java

@Entity 
public class Client extends AbstractEntity<Integer> { 

private static final long serialVersionUID = 1L; 

public static final String FIND_BY_NAME = "Client.FIND_BY_NAME"; 

public static final String COUNT_BY_NAME = "Client.COUNT_BY_NAME"; 

@Basic(optional = false) 
@Column(nullable = false, length = 125) 
private String name; 

@ManyToMany(fetch = FetchType.LAZY) 
@JoinTable(inverseJoinColumns = { 
    @JoinColumn(name = "trade_order_management_system_id")}, uniqueConstraints = 
@UniqueConstraint(name = "UK_client_trade_order_mgmt_client_id_trade_order_mgmt_id", 
columnNames = {"client_id", "trade_order_management_system_id"})) 
@ForeignKey(name = "FK_client_trade_order_management_systems_client_id", 
inverseName = "FK_client_trade_order_mgmt_sys_trade_order_management_system_id") 
private List<TradeOrderManagementSystem> tradeOrderManagementSystems; 

public Client() { 
} 

public Client(Integer id) { 
    this.id = id; 
} 

public Client(Integer id, String name) { 
    this.id = id; 
    this.name = name; 
} 

public String getName() { 
    return name; 
} 

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

public List<TradeOrderManagementSystem> getTradeOrderManagementSystems() { 
    return tradeOrderManagementSystems; 
} 

public void setTradeOrderManagementSystems(List<TradeOrderManagementSystem> tradeOrderManagementSystems) { 
    this.tradeOrderManagementSystems = tradeOrderManagementSystems; 
} 

@Override 
public boolean equals(Object object) { 
    // TODO: Warning - this method won't work in the case the id fields are not set 
    if (!(object instanceof Client)) { 
     return false; 
    } 
    Client other = (Client) object; 
    if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { 
     return false; 
    } 
    return true; 
} 

}

методы обслуживания

public abstract class CrudService<T, ID extends Serializable> extends DAOImpl<T, ID> { 

/** 
* Updates an entity from an existing entity. 
* 
* @since 0.0.1 
* 
* @param entity 
* @return the managed instance of the updated entity 
*/ 
@Override 
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED) 
public T update(T entity, ID id) { 
    return super.update(assignDefaultValues(entity), id); 
} 

}

public abstract class DAOImpl<T, ID extends Serializable> implements DAO<T, ID> { 

private Class<T> persistentClass; 

@PersistenceContext(unitName = "krfsPersistenceUnit") 
protected EntityManager entityManager; 

/** 
* Instantiates an instance of this class and sets the <code>persistentClass</code> 
* based on the identifier type 
* 
* @since 0.0.1 
*/ 
public DAOImpl() { 
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
} 

/** 
* @since 0.0.1 
* 
* @return the type to be persisted 
*/ 
@Override 
public Class<T> getPersistentClass() { 
    return persistentClass; 
} 

/** 
* Updates an entity from an existing entity. 
* 
* @since 0.0.1 
* 
* @param entity 
* @param id the identifier of the entity 
* 
* @return the managed instance of the updated entity 
*/ 
@Override 
public T update(T entity, ID id) { 
    //Find a managed instance of the entity first and copy the properties 
    //to the passed in entity before merging. This ensures that entityManager 
    //will not create a new entity with merge. 
    Object ref = this.entityManager.getReference(persistentClass, id); 
    if (ref != null) { 
     BeanUtils.copyProperties(entity, ref); 
    } 
    return (T) this.entityManager.merge(ref); 
} 

}

+0

Я также знаю, что использование какого-либо DTO для модели также является решением, но просто не имеет смысла, что часть модели уничтожена, поскольку форма определяет только определенные поля Модели.Если я подталкиваю модель к ModelAndView, форма должна сохранять только то, что указано в Модели! – dukethrash

ответ

1

Вы на самом деле не дает достаточно деталей (в частности, код, показывающий, как сохранить значения из формы помогут), но я подозреваю, что вы объединение отдельного объекта с атрибутами null. И из-за того, как работает merge (он копирует состояние отделяемого объекта на объект с тем же идентификатором базы данных, загруженным в контекст персистентности), вы получаете NULL.

Вам нужно либо:

  • каким-то образом держать отделенную сущность, копировать значения образуют форму в нее, а затем merge его ~ или ~
  • реализовать «ручное объединение» т.е. загрузить объект для обновления с использованием своего идентификатора, скопируйте новые значения из модели и дайте JPA обновить его.

Если я пропустил этот пункт, просьба предоставить более подробную информацию, чтобы понять проблему.

Обновление: Я не понимаю ваш код. Вы копируете свойства отrefдоentity (отсоединенный клиент, исходящий из представления), затем слияние ref ... Нет, я не понимаю.

+0

Я считаю, что вы, возможно, пропустили эту точку, потому что если я сделаю слияние, тогда поля будут исключены из-за того, что они не существуют в форме. Я предоставил некоторый код для подробностей. Благодаря! – dukethrash

+0

@dukethrash Я думаю, что вы неправильно поняли мой ответ. В любом случае, мне очень хотелось бы знать, что делает метод 'clientService.update (Client)', это как-то ключ к проблеме. Разве вы не думаете, что показать эту часть было бы полезно? –

+0

Я опубликовал методы обновления. Как ни странно, обратите внимание, что объект, передаваемый методу обновления, имеет только нулевые значения, кроме TradeOrderManagementSystem. Я понимаю, что можно скопировать значения из формы и слияния, но это похоже на подход DTO. Для меня не имеет смысла, что Spring стирает все поля модели и заменяет только те из них, которые указаны в форме. Если я clientService.findById и нажимаю клиент как модель, он должен оставаться как Модель и изменять только то, что было на форме, но это не похоже на природу Spring MVC. – dukethrash

Смежные вопросы