Skip to content

PetClinic - JPA, EntityManagerClinic.storeOwner need to use persist() rather than merge(), web.xml need to configure OpenEntityManagerInViewFilter for lazy load, [SPR-3045] #7731

@spring-projects-issues

Description

@spring-projects-issues

Henry Lai opened SPR-3045 and commented

inside the org.springframework.samples.petclinic.webAddOwnerForm.onSubmit method
the owner.getId() is always null!

protected ModelAndView onSubmit(Object command) throws ServletException {
	Owner owner = (Owner) command;
	// delegate the insert to the Business layer
	getClinic().storeOwner(owner);
	return new ModelAndView(getSuccessView(), "ownerId", owner.getId());
}

in org.springframework.samples.petclinic.jpa.EntityManagerClinic

public void storeOwner(Owner owner) throws DataAccessException {
	em.merge(owner);
}

when the owner object is unmanaged, invoking entityManager.merge( owner) return a different manage instance of owner, the id is assigned to the manage instance not the unmanage instance.

changed to

public void storeOwner(Owner owner) throws DataAccessException {
    if ( owner.getId() == null ){
         em.persist(owner);
    } else {
         em.merge(owner);
    }

ClinicController

public ModelAndView ownerHandler(HttpServletRequest request, HttpServletResponse response) {
	Owner owner = this.clinic.loadOwner(ServletRequestUtils.getIntParameter(request, "ownerId", 0));
	if (owner == null) {
		return new ModelAndView("findOwnersRedirect");
	}
	return new ModelAndView().addObject(owner);
}

the clinic.loadOwner method only loads the owner, does not load the owner.pets and pet.visits
therefore when the view owner.jsp reference owner.pets, and pet.visits, they are not shown, even though they exist in the DB, but did not get lazy load exception.

after configuring the OpenEntityManagerInViewFilter in web.xml the problem was resolved. This should be documented in the petclinic jpa docs.


AddPetForm

protected Object formBackingObject(HttpServletRequest request) throws ServletException {
	Owner owner = getClinic().loadOwner(ServletRequestUtils.getRequiredIntParameter(request, "ownerId"));
	Pet pet = new Pet();
	owner.addPet(pet);
	return pet;
}

the formBackingObject method adds a new pet to the owner object, which cause the pet object to be inserted to the DB, the next time the persistence context is flush, at this point most of the fields in the pet object is null, the flush result in null contraint exception.
The flush was occur inside referenceData method, in getClinic().getPetTypes() resulting in null contraint exception.

changed the code as follows

protected Object formBackingObject(HttpServletRequest request) throws ServletException {
	Owner owner = getClinic().loadOwner(ServletRequestUtils.getRequiredIntParameter(request, "ownerId"));
	Pet pet = new Pet();
	pet.setOwner( owner );
	return pet;
}

Affects: 2.0.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions