mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-04-26 12:22:47 +00:00
Remove manual id management in child entities
This is reverting a workaround for a Hibernate "feature". There's no need for the child entities (Pet and Visit) to know about their parent (foreign key). Hibernate can manage that just fine with a @JoinColumn. But it needs a nullable foreign key column in the DB schema. That's the downside. The upside is much less code in Java.
This commit is contained in:
parent
43beff91a3
commit
b559077f14
10 changed files with 25 additions and 60 deletions
|
@ -16,22 +16,19 @@
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.persistence.CascadeType;
|
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.FetchType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.OrderBy;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.validation.constraints.Digits;
|
import javax.validation.constraints.Digits;
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
import org.springframework.beans.support.MutableSortDefinition;
|
|
||||||
import org.springframework.beans.support.PropertyComparator;
|
|
||||||
import org.springframework.core.style.ToStringCreator;
|
import org.springframework.core.style.ToStringCreator;
|
||||||
import org.springframework.samples.petclinic.model.Person;
|
import org.springframework.samples.petclinic.model.Person;
|
||||||
|
|
||||||
|
@ -60,8 +57,10 @@ public class Owner extends Person {
|
||||||
@Digits(fraction = 0, integer = 10)
|
@Digits(fraction = 0, integer = 10)
|
||||||
private String telephone;
|
private String telephone;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "ownerId", fetch = FetchType.EAGER)
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
private Set<Pet> pets;
|
@JoinColumn(name = "owner_id")
|
||||||
|
@OrderBy("name")
|
||||||
|
private List<Pet> pets = new ArrayList<>();
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return this.address;
|
return this.address;
|
||||||
|
@ -87,28 +86,14 @@ public class Owner extends Person {
|
||||||
this.telephone = telephone;
|
this.telephone = telephone;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<Pet> getPetsInternal() {
|
|
||||||
if (this.pets == null) {
|
|
||||||
this.pets = new HashSet<>();
|
|
||||||
}
|
|
||||||
return this.pets;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setPetsInternal(Set<Pet> pets) {
|
|
||||||
this.pets = pets;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Pet> getPets() {
|
public List<Pet> getPets() {
|
||||||
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
|
return this.pets;
|
||||||
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
|
|
||||||
return Collections.unmodifiableList(sortedPets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPet(Pet pet) {
|
public void addPet(Pet pet) {
|
||||||
if (pet.isNew()) {
|
if (pet.isNew()) {
|
||||||
getPetsInternal().add(pet);
|
getPets().add(pet);
|
||||||
}
|
}
|
||||||
pet.setOwnerId(getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,7 +111,7 @@ public class Owner extends Person {
|
||||||
* @return a pet if pet id is already in use
|
* @return a pet if pet id is already in use
|
||||||
*/
|
*/
|
||||||
public Pet getPet(Integer id) {
|
public Pet getPet(Integer id) {
|
||||||
for (Pet pet : getPetsInternal()) {
|
for (Pet pet : getPets()) {
|
||||||
if (!pet.isNew()) {
|
if (!pet.isNew()) {
|
||||||
Integer compId = pet.getId();
|
Integer compId = pet.getId();
|
||||||
if (compId.equals(id)) {
|
if (compId.equals(id)) {
|
||||||
|
@ -144,7 +129,7 @@ public class Owner extends Person {
|
||||||
*/
|
*/
|
||||||
public Pet getPet(String name, boolean ignoreNew) {
|
public Pet getPet(String name, boolean ignoreNew) {
|
||||||
name = name.toLowerCase();
|
name = name.toLowerCase();
|
||||||
for (Pet pet : getPetsInternal()) {
|
for (Pet pet : getPets()) {
|
||||||
if (!ignoreNew || !pet.isNew()) {
|
if (!ignoreNew || !pet.isNew()) {
|
||||||
String compName = pet.getName();
|
String compName = pet.getName();
|
||||||
compName = compName == null ? "" : compName.toLowerCase();
|
compName = compName == null ? "" : compName.toLowerCase();
|
||||||
|
|
|
@ -52,17 +52,11 @@ public class Pet extends NamedEntity {
|
||||||
@JoinColumn(name = "type_id")
|
@JoinColumn(name = "type_id")
|
||||||
private PetType type;
|
private PetType type;
|
||||||
|
|
||||||
@Column
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
private Integer ownerId;
|
@JoinColumn(name = "pet_id")
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "petId", fetch = FetchType.LAZY)
|
|
||||||
@OrderBy("visit_date ASC")
|
@OrderBy("visit_date ASC")
|
||||||
private Set<Visit> visits = new LinkedHashSet<>();
|
private Set<Visit> visits = new LinkedHashSet<>();
|
||||||
|
|
||||||
public void setOwnerId(Integer ownerId) {
|
|
||||||
this.ownerId = ownerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBirthDate(LocalDate birthDate) {
|
public void setBirthDate(LocalDate birthDate) {
|
||||||
this.birthDate = birthDate;
|
this.birthDate = birthDate;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +79,6 @@ public class Pet extends NamedEntity {
|
||||||
|
|
||||||
public void addVisit(Visit visit) {
|
public void addVisit(Visit visit) {
|
||||||
getVisits().add(visit);
|
getVisits().add(visit);
|
||||||
visit.setPetId(this.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,8 @@ public class Visit extends BaseEntity {
|
||||||
private LocalDate date;
|
private LocalDate date;
|
||||||
|
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
@Column
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@Column
|
|
||||||
private Integer petId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of Visit for the current date
|
* Creates a new instance of Visit for the current date
|
||||||
*/
|
*/
|
||||||
|
@ -69,12 +65,4 @@ public class Visit extends BaseEntity {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getPetId() {
|
|
||||||
return this.petId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPetId(Integer petId) {
|
|
||||||
this.petId = petId;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,12 +78,13 @@ 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(@ModelAttribute Owner owner, @Valid Visit visit, BindingResult result) {
|
public String processNewVisitForm(@ModelAttribute Owner owner, @PathVariable("petId") int petId, @Valid Visit visit,
|
||||||
|
BindingResult result) {
|
||||||
if (result.hasErrors()) {
|
if (result.hasErrors()) {
|
||||||
return "pets/createOrUpdateVisitForm";
|
return "pets/createOrUpdateVisitForm";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
owner.getPet(visit.getPetId()).addVisit(visit);
|
owner.getPet(petId).addVisit(visit);
|
||||||
this.owners.save(owner);
|
this.owners.save(owner);
|
||||||
return "redirect:/owners/{ownerId}";
|
return "redirect:/owners/{ownerId}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ CREATE TABLE pets (
|
||||||
name VARCHAR(30),
|
name VARCHAR(30),
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
type_id INTEGER NOT NULL,
|
type_id INTEGER NOT NULL,
|
||||||
owner_id INTEGER NOT NULL
|
owner_id INTEGER
|
||||||
);
|
);
|
||||||
ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id);
|
ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id);
|
||||||
ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id);
|
ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id);
|
||||||
|
@ -56,7 +56,7 @@ CREATE INDEX pets_name ON pets (name);
|
||||||
|
|
||||||
CREATE TABLE visits (
|
CREATE TABLE visits (
|
||||||
id INTEGER IDENTITY PRIMARY KEY,
|
id INTEGER IDENTITY PRIMARY KEY,
|
||||||
pet_id INTEGER NOT NULL,
|
pet_id INTEGER,
|
||||||
visit_date DATE,
|
visit_date DATE,
|
||||||
description VARCHAR(255)
|
description VARCHAR(255)
|
||||||
);
|
);
|
||||||
|
|
|
@ -48,7 +48,7 @@ CREATE TABLE pets (
|
||||||
name VARCHAR(30),
|
name VARCHAR(30),
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
type_id INTEGER NOT NULL,
|
type_id INTEGER NOT NULL,
|
||||||
owner_id INTEGER NOT NULL
|
owner_id INTEGER
|
||||||
);
|
);
|
||||||
ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id);
|
ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id);
|
||||||
ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id);
|
ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id);
|
||||||
|
@ -56,7 +56,7 @@ CREATE INDEX pets_name ON pets (name);
|
||||||
|
|
||||||
CREATE TABLE visits (
|
CREATE TABLE visits (
|
||||||
id INTEGER IDENTITY PRIMARY KEY,
|
id INTEGER IDENTITY PRIMARY KEY,
|
||||||
pet_id INTEGER NOT NULL,
|
pet_id INTEGER,
|
||||||
visit_date DATE,
|
visit_date DATE,
|
||||||
description VARCHAR(255)
|
description VARCHAR(255)
|
||||||
);
|
);
|
||||||
|
|
|
@ -40,7 +40,7 @@ CREATE TABLE IF NOT EXISTS pets (
|
||||||
name VARCHAR(30),
|
name VARCHAR(30),
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
type_id INT(4) UNSIGNED NOT NULL,
|
type_id INT(4) UNSIGNED NOT NULL,
|
||||||
owner_id INT(4) UNSIGNED NOT NULL,
|
owner_id INT(4) UNSIGNED,
|
||||||
INDEX(name),
|
INDEX(name),
|
||||||
FOREIGN KEY (owner_id) REFERENCES owners(id),
|
FOREIGN KEY (owner_id) REFERENCES owners(id),
|
||||||
FOREIGN KEY (type_id) REFERENCES types(id)
|
FOREIGN KEY (type_id) REFERENCES types(id)
|
||||||
|
@ -48,7 +48,7 @@ CREATE TABLE IF NOT EXISTS pets (
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS visits (
|
CREATE TABLE IF NOT EXISTS visits (
|
||||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
pet_id INT(4) UNSIGNED NOT NULL,
|
pet_id INT(4) UNSIGNED,
|
||||||
visit_date DATE,
|
visit_date DATE,
|
||||||
description VARCHAR(255),
|
description VARCHAR(255),
|
||||||
FOREIGN KEY (pet_id) REFERENCES pets(id)
|
FOREIGN KEY (pet_id) REFERENCES pets(id)
|
||||||
|
|
|
@ -38,14 +38,14 @@ CREATE TABLE IF NOT EXISTS pets (
|
||||||
name TEXT,
|
name TEXT,
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
type_id INT NOT NULL REFERENCES types (id),
|
type_id INT NOT NULL REFERENCES types (id),
|
||||||
owner_id INT NOT NULL REFERENCES owners (id)
|
owner_id INT REFERENCES owners (id)
|
||||||
);
|
);
|
||||||
CREATE INDEX ON pets (name);
|
CREATE INDEX ON pets (name);
|
||||||
CREATE INDEX ON pets (owner_id);
|
CREATE INDEX ON pets (owner_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS visits (
|
CREATE TABLE IF NOT EXISTS visits (
|
||||||
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||||
pet_id INT NOT NULL REFERENCES pets (id),
|
pet_id INT REFERENCES pets (id),
|
||||||
visit_date DATE,
|
visit_date DATE,
|
||||||
description TEXT
|
description TEXT
|
||||||
);
|
);
|
||||||
|
|
|
@ -75,11 +75,11 @@ class OwnerControllerTests {
|
||||||
Pet max = new Pet();
|
Pet max = new Pet();
|
||||||
PetType dog = new PetType();
|
PetType dog = new PetType();
|
||||||
dog.setName("dog");
|
dog.setName("dog");
|
||||||
max.setId(1);
|
|
||||||
max.setType(dog);
|
max.setType(dog);
|
||||||
max.setName("Max");
|
max.setName("Max");
|
||||||
max.setBirthDate(LocalDate.now());
|
max.setBirthDate(LocalDate.now());
|
||||||
george.setPetsInternal(Collections.singleton(max));
|
george.addPet(max);
|
||||||
|
max.setId(1);
|
||||||
return george;
|
return george;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,7 +95,6 @@ class OwnerControllerTests {
|
||||||
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());
|
||||||
visit.setPetId(george.getPet("Max").getId());
|
|
||||||
george.getPet("Max").getVisits().add(visit);
|
george.getPet("Max").getVisits().add(visit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,6 @@ class ClinicServiceTests {
|
||||||
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();
|
||||||
assertThat(visitArr[0].getPetId()).isEqualTo(7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue