Also remove VisitRepository

Rely on Hibernate to do lazy loading on visits.
This commit is contained in:
Dave Syer 2022-01-05 08:55:24 +00:00 committed by Dave Syer
parent a5da14ae2f
commit 58fe6298f8
8 changed files with 43 additions and 113 deletions

View file

@ -23,7 +23,6 @@ import javax.validation.Valid;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
@ -48,11 +47,8 @@ class OwnerController {
private final OwnerRepository owners; private final OwnerRepository owners;
private final VisitRepository visits; public OwnerController(OwnerRepository clinicService) {
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
this.owners = clinicService; this.owners = clinicService;
this.visits = visits;
} }
@InitBinder @InitBinder
@ -161,7 +157,7 @@ class OwnerController {
ModelAndView mav = new ModelAndView("owners/ownerDetails"); ModelAndView mav = new ModelAndView("owners/ownerDetails");
Owner owner = this.owners.findById(ownerId); Owner owner = this.owners.findById(ownerId);
for (Pet pet : owner.getPets()) { for (Pet pet : owner.getPets()) {
pet.setVisitsInternal(visits.findByPetId(pet.getId())); pet.getVisits();
} }
mav.addObject(owner); mav.addObject(owner);
return mav; return mav;

View file

@ -16,23 +16,20 @@
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient;
import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
@ -59,7 +56,8 @@ public class Pet extends NamedEntity {
@Column @Column
private Integer ownerId; private Integer ownerId;
@Transient @OneToMany(cascade = CascadeType.ALL, mappedBy = "petId", fetch = FetchType.LAZY)
@OrderBy("visit_date ASC")
private Set<Visit> visits = new LinkedHashSet<>(); private Set<Visit> visits = new LinkedHashSet<>();
public void setOwnerId(Integer ownerId) { public void setOwnerId(Integer ownerId) {
@ -82,25 +80,12 @@ public class Pet extends NamedEntity {
this.type = type; this.type = type;
} }
protected Set<Visit> getVisitsInternal() { public Collection<Visit> getVisits() {
if (this.visits == null) {
this.visits = new HashSet<>();
}
return this.visits; return this.visits;
} }
protected void setVisitsInternal(Collection<Visit> visits) {
this.visits = new LinkedHashSet<>(visits);
}
public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits);
}
public void addVisit(Visit visit) { public void addVisit(Visit visit) {
getVisitsInternal().add(visit); getVisits().add(visit);
visit.setPetId(this.getId()); visit.setPetId(this.getId());
} }

View file

@ -40,10 +40,10 @@ public class Visit extends BaseEntity {
private LocalDate date; private LocalDate date;
@NotEmpty @NotEmpty
@Column(name = "description") @Column
private String description; private String description;
@Column(name = "pet_id") @Column
private Integer petId; private Integer petId;
/** /**

View file

@ -15,15 +15,19 @@
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import javax.validation.Valid; import org.springframework.web.bind.annotation.ModelAttribute;
import java.util.Map; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
@ -35,12 +39,9 @@ import java.util.Map;
@Controller @Controller
class VisitController { class VisitController {
private final VisitRepository visits;
private final OwnerRepository owners; private final OwnerRepository owners;
public VisitController(VisitRepository visits, OwnerRepository owners) { public VisitController(OwnerRepository owners) {
this.visits = visits;
this.owners = owners; this.owners = owners;
} }
@ -61,7 +62,6 @@ class VisitController {
Map<String, Object> model) { Map<String, Object> model) {
Owner owner = this.owners.findById(ownerId); Owner owner = this.owners.findById(ownerId);
Pet pet = owner.getPet(petId); Pet pet = owner.getPet(petId);
pet.setVisitsInternal(this.visits.findByPetId(petId));
model.put("pet", pet); model.put("pet", pet);
Visit visit = new Visit(); Visit visit = new Visit();
pet.addVisit(visit); pet.addVisit(visit);
@ -78,12 +78,14 @@ class VisitController {
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is
// called // called
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) { public String processNewVisitForm(@PathVariable("ownerId") int ownerId, @Valid Visit visit, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} }
else { else {
this.visits.save(visit); Owner owner = this.owners.findById(ownerId);
owner.getPet(visit.getPetId()).addVisit(visit);
this.owners.save(owner);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }

View file

@ -1,46 +0,0 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.visit;
import org.springframework.dao.DataAccessException;
import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.BaseEntity;
import java.util.List;
/**
* Repository class for <code>Visit</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
*
* @author Ken Krebs
* @author Juergen Hoeller
* @author Sam Brannen
* @author Michael Isvy
*/
public interface VisitRepository extends Repository<Visit, Integer> {
/**
* Save a <code>Visit</code> to the data store, either inserting or updating it.
* @param visit the <code>Visit</code> to save
* @see BaseEntity#isNew
*/
void save(Visit visit) throws DataAccessException;
List<Visit> findByPetId(Integer petId);
}

View file

@ -47,7 +47,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
/** /**
@ -66,9 +65,6 @@ class OwnerControllerTests {
@MockBean @MockBean
private OwnerRepository owners; private OwnerRepository owners;
@MockBean
private VisitRepository visits;
private Owner george() { private Owner george() {
Owner george = new Owner(); Owner george = new Owner();
george.setId(TEST_OWNER_ID); george.setId(TEST_OWNER_ID);
@ -91,15 +87,17 @@ class OwnerControllerTests {
@BeforeEach @BeforeEach
void setup() { void setup() {
Owner george = george();
given(this.owners.findByLastName(eq("Franklin"), any(Pageable.class))) given(this.owners.findByLastName(eq("Franklin"), any(Pageable.class)))
.willReturn(new PageImpl<Owner>(Lists.newArrayList(george()))); .willReturn(new PageImpl<Owner>(Lists.newArrayList(george)));
given(this.owners.findAll(any(Pageable.class))).willReturn(new PageImpl<Owner>(Lists.newArrayList(george()))); given(this.owners.findAll(any(Pageable.class))).willReturn(new PageImpl<Owner>(Lists.newArrayList(george)));
given(this.owners.findById(TEST_OWNER_ID)).willReturn(george()); given(this.owners.findById(TEST_OWNER_ID)).willReturn(george);
Visit visit = new Visit(); Visit visit = new Visit();
visit.setDate(LocalDate.now()); visit.setDate(LocalDate.now());
given(this.visits.findByPetId(george().getPet("Max").getId())).willReturn(Collections.singletonList(visit)); visit.setPetId(george.getPet("Max").getId());
george.getPet("Max").getVisits().add(visit);
} }

View file

@ -16,19 +16,20 @@
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/** /**
* Test class for {@link VisitController} * Test class for {@link VisitController}
* *
@ -44,9 +45,6 @@ class VisitControllerTests {
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@MockBean
private VisitRepository visits;
@MockBean @MockBean
private OwnerRepository owners; private OwnerRepository owners;

View file

@ -36,7 +36,6 @@ import org.springframework.samples.petclinic.owner.PetType;
import org.springframework.samples.petclinic.vet.Vet; import org.springframework.samples.petclinic.vet.Vet;
import org.springframework.samples.petclinic.vet.VetRepository; import org.springframework.samples.petclinic.vet.VetRepository;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -76,9 +75,6 @@ class ClinicServiceTests {
@Autowired @Autowired
protected OwnerRepository owners; protected OwnerRepository owners;
@Autowired
protected VisitRepository visits;
@Autowired @Autowired
protected VetRepository vets; protected VetRepository vets;
@ -205,17 +201,18 @@ class ClinicServiceTests {
Visit visit = new Visit(); Visit visit = new Visit();
pet7.addVisit(visit); pet7.addVisit(visit);
visit.setDescription("test"); visit.setDescription("test");
this.visits.save(visit);
this.owners.save(owner6); this.owners.save(owner6);
owner6 = this.owners.findById(6); owner6 = this.owners.findById(6);
assertThat(pet7.getVisits().size()).isEqualTo(found + 1); assertThat(pet7.getVisits().size()).isEqualTo(found + 1);
assertThat(visit.getId()).isNotNull(); assertThat(pet7.getVisits()).allMatch(value -> value.getId() != null);
} }
@Test @Test
void shouldFindVisitsByPetId() throws Exception { void shouldFindVisitsByPetId() throws Exception {
Collection<Visit> visits = this.visits.findByPetId(7); Owner owner6 = this.owners.findById(6);
Pet pet7 = owner6.getPet(7);
Collection<Visit> visits = pet7.getVisits();
assertThat(visits).hasSize(2); assertThat(visits).hasSize(2);
Visit[] visitArr = visits.toArray(new Visit[visits.size()]); Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
assertThat(visitArr[0].getDate()).isNotNull(); assertThat(visitArr[0].getDate()).isNotNull();