Pregunta

Estamos utilizando beans de entidad JPA como nuestro modelo para el regulador Spring MVC en una página JSP. Una de nuestras páginas JSP es una vista parcial de esta entidad, que no muestra todas las propiedades. Siempre tratamos de actualizar nuestra entidad que utiliza la capa de servicio del controlador sólo las propiedades que se utilizan en el formulario JSP se conservan y todos los otros son anuladas a cabo. ¿Cuál es la forma correcta de manejar esta situación? No quiero tener que especificar los campos ocultos en el formulario.

Así que en este caso cuando el controlador llama al método service.update (cliente) el campo de nombre será nula, ya que no existe en la 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">

controlador

@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;
}

}

métodos servicio

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);
}

}

¿Fue útil?

Solución

Usted no está realmente dando suficientes detalles (en concreto, el código que muestra cómo guardar los valores de la forma ayudaría) pero sospecha que está la fusión de una entidad independiente con atributos null. Y debido a las obras de manera merge (copia el estado de la entidad separada en una entidad con el mismo identificador de base de datos cargada en el contexto de persistencia), se obtiene valores NULL.

Es necesario que sea:

  • alguna manera a mantener la entidad individual, copiar los valores forman la forma en ella, y luego merge que ~ o ~
  • implementar una "fusión manual" es decir, cargar la entidad para actualizar utilizando utilizando su ID, copia los nuevos valores del modelo y dejar que la actualización de la APP.

Si echaba de menos el punto, por favor proporcionar más detalles para entender el problema.

Actualización: No entiendo su código. Estas propiedades ref a entity (el cliente individual procedente de la vista), entonces la fusión ref ... No, no lo entiendo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top