Joe Essey
Joe Essey

Reputation: 3527

Spring MVC, attempting to edit but creating new objects

I have an MVC app that is creating new offices instead of updating them on when using an edit form. Please help me understand why this is happening.

Search method that populates the search results:

@RequestMapping(value = "/searchResults", method = RequestMethod.POST)
public ModelAndView search(@RequestParam String searchCriteria, HttpServletRequest request) {
    List<Office> offices = officeServiceImpl.search(searchCriteria);
    return new ModelAndView("searchResults", "offices", offices);
}

Here's what the link to the edit form looks like on the search results page:

<a href="${pageContext.request.contextPath}/app/office/${office.getId()}/edit" class="btn btn-success">Edit Office</a>

Here is the Controller's edit GET method that populates the form with the existing Office:

@RequestMapping(value = "/{officeId}/edit", method = RequestMethod.GET)
@Transactional(noRollbackFor=NoResultException.class)
public ModelAndView initUpdateOfficeForm(
    @PathVariable("officeId") Long officeId, Model model) {
    Office office = officeServiceImpl.find(officeId);
    //prepareEditFormModelAndView(office) just converts some objects to strings for typeahead form population
    return prepareEditFormModelAndView(office);
}

Here is the edit POST method:

@RequestMapping(value = "/{officeId}/edit", method = RequestMethod.POST)
public ModelAndView processUpdateOfficeForm(@ModelAttribute("office") @Valid Office office,
        BindingResult result, SessionStatus status) {
    if (! "united states of america".equals(office.getFolderStrings().toLowerCase())) {
        //This portion of code converts the typeahead strings to objects
        result = tryCountries(office, result);
        result = tryDepartments(office, result);
        result = tryEmployees(office, result);
        }
        if (result.hasErrors()) {
        return prepareEditFormModelAndView(office);
    } else {
        officeServiceImpl.save(office);
        status.setComplete();
        return new ModelAndView("editResult", "office", office);
    }
}

officeServiceImpl calls officeRepositoryImpl method save which looks like:

@Override
public Office save(Office office) {
    em.merge(office);
    em.flush();
    return office;
}

Thanks

Edit: Adding prepareEditFormModelAndView(office), This method attempts to build strings from associated objects:

@Transactional(noRollbackFor={NoResultException.class, IndexOutOfBoundsException.class})
private ModelAndView prepareEditFormModelAndView(Office office) {
    String departmentStrings = "";
    String employeeStrings = "";

    List<OOM> officeOOMs = new ArrayList<OOM>();
    StringBuilder sb = new StringBuilder();
    try {
        officeOOMs = oomServiceImpl.getOOMsForCurrentOffice(office.getId());
    } catch (NoResultException e) {
        officeOOMs = null;
    }
    for (OOM o : officeOOMs) {
        try {
            Employee tempEmployee = employeeServiceImpl.find(o
                    .getEmployeeId());
            sb.append(tempEmployee.getDisplayName() + ", ");
        } catch (NoResultException e) {
            sb.append("Not found in system");
        }
    }
    employeeStrings = sb.toString();

    if ((! "".equals(office.getDepartmentStringsOnForm())) && office.getDepartmentStringsOnForm() != null) {
        departmentStrings = office.getDepartmentStringsOnForm();
    }
    String folderStrings = "";
    try {
        folderStrings = kmlFolderServiceImpl.getInternationalOfficeString(office.getId());
        LOGGER.info("Folder Strings: " + folderStrings);
    } catch (NoResultException e) {
        folderStrings = "";
        LOGGER.info("Folder Strings: " + "no result");
    }
    boolean isInternational = office.isInternational();
    ModelAndView result = new ModelAndView("editOfficeForm", "office", office);
    result.addObject("departmentStrings", departmentStrings);
    result.addObject("isInternational", isInternational);
    result.addObject("folderStrings", folderStrings);
    result.addObject("employeeStrings", employeeStrings);
    return result;
}

Upvotes: 2

Views: 968

Answers (1)

geoand
geoand

Reputation: 64011

I am adding a previous comment here, for better clarification. According to the OP the following fixes the problem:

When the ID is not in the form then when the model is posted back no ID is set to the entity making the persistence provider believe it is new entity. Therefor the most obvious solution is to post the ID of the entity as well in the save operation (probably using a hidden field).

Another solution would be to try to load the entity in the database based on some business key to see if the entity is new or not.

Upvotes: 2

Related Questions