#346 - Demonstrating the use of @Query with and without @Modifying.

Added assertions to existing tests to verify they work as intended.

Changed Model to a value object because we can.
This commit is contained in:
Jens Schauder
2018-03-12 09:43:55 +01:00
committed by Oliver Gierke
parent 2571c89af0
commit 68a15b0f5a
7 changed files with 139 additions and 36 deletions

View File

@@ -1,6 +1,5 @@
== Spring Data JDBC basics
=== SimpleEntityTests
This example demonstrate basic usage of JDBC based repositories.
@@ -26,3 +25,6 @@ This is achieved by providing a custom `NamingStrategy` which maps both to the s
* When the database returns a data type for query which Spring Data JDBC doesn't map out of the box a custom conversion can be registered using a `ConversionCustomizer` as demonstrated in `AggregateContext.conversionCustomizer()`.
* `LegoSetRepository` has methods that utilize `@Query` annotations.
* Note that `Model` is a value class, i.e. it is immutable, and doesn't have an ID.

View File

@@ -38,33 +38,32 @@ import org.springframework.lang.Nullable;
@Configuration
@EnableJdbcRepositories
public class AggregateConfiguration {
final AtomicInteger id = new AtomicInteger(0);
@Bean
public ApplicationListener<?> idSetting() {
final AtomicInteger id = new AtomicInteger(0);
return (ApplicationListener<BeforeSaveEvent>) event -> {
Object entity = event.getEntity();
if (entity instanceof LegoSet) {
LegoSet legoSet = (LegoSet) entity;
if (legoSet.getId() == 0) {
legoSet.setId(id.incrementAndGet());
}
Manual manual = legoSet.getManual();
if (manual != null) {
manual.setId((long) legoSet.getId());
}
if (event.getEntity() instanceof LegoSet) {
setIds((LegoSet) event.getEntity());
}
};
}
private void setIds(LegoSet legoSet) {
if (legoSet.getId() == 0) {
legoSet.setId(id.incrementAndGet());
}
Manual manual = legoSet.getManual();
if (manual != null) {
manual.setId((long) legoSet.getId());
}
}
@Bean
public NamingStrategy namingStrategy() {

View File

@@ -77,10 +77,7 @@ public class LegoSet {
public void addModel(String name, String description) {
Model model = new Model();
model.name = name;
model.description = description;
Model model = new Model(name, description);
models.put(name, model);
}
}

View File

@@ -15,11 +15,28 @@
*/
package example.springdata.jdbc.basics.aggregate;
import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* A repository for {@link LegoSet}.
*
* @author Jens Schauder
*/
interface LegoSetRepository extends CrudRepository<LegoSet, Integer> {}
interface LegoSetRepository extends CrudRepository<LegoSet, Integer> {
@Query("SELECT m.name modelName, m.description, l.name setName" +
" FROM model m" +
" JOIN LegoSet l" +
" ON m.legoset = l.id" +
" WHERE :age BETWEEN l.minAge and l.maxAge")
List<ModelReport> reportModelForAge(@Param("age") int age);
@Modifying
@Query("UPDATE model set name = lower(name) WHERE name <> lower(name)")
int lowerCaseMapKeys();
}

View File

@@ -15,18 +15,16 @@
*/
package example.springdata.jdbc.basics.aggregate;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import lombok.Value;
/**
* One of potentially multiple models that can be build from a single {@link LegoSet}. No getters or setters needed.
*
* @author Jens Schauder
*/
@ToString
@Value
public class Model {
@Id String name;
String name;
String description;
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2018 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
*
* http://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 example.springdata.jdbc.basics.aggregate;
import lombok.Value;
/**
* @author Jens Schauder
*/
@Value
public class ModelReport {
private final String modelName;
private final String description;
private final String setName;
}

View File

@@ -15,15 +15,21 @@
*/
package example.springdata.jdbc.basics.aggregate;
import static org.assertj.core.api.Assertions.*;
import example.springdata.jdbc.basics.Output;
import java.time.Period;
import java.util.Arrays;
import java.util.List;
import org.assertj.core.groups.Tuple;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureJdbc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
/**
@@ -34,6 +40,7 @@ import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AggregateConfiguration.class)
@AutoConfigureJdbc
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class AggregateTests {
@Autowired LegoSetRepository repository;
@@ -41,34 +48,88 @@ public class AggregateTests {
@Test
public void exerciseSomewhatComplexEntity() {
LegoSet smallCar = createLegoSet();
LegoSet smallCar = createLegoSet("Small Car 01", 5, 12);
smallCar.setManual(new Manual("Just put all the pieces together in the right order", "Jens Schauder"));
smallCar.addModel("suv", "SUV with sliding doors.");
smallCar.addModel("roadster", "Slick red roadster.");
repository.save(smallCar);
Output.list(repository.findAll(), "Original LegoSet");
Iterable<LegoSet> legoSets = repository.findAll();
Output.list(legoSets, "Original LegoSet");
checkLegoSets(legoSets, "Just put all the pieces together in the right order", 2);
smallCar.getManual().setText("Just make it so it looks like a car.");
smallCar.addModel("pickup", "A pickup truck with some tools in the back.");
repository.save(smallCar);
Output.list(repository.findAll(), "Updated");
legoSets = repository.findAll();
Output.list(legoSets, "Updated");
checkLegoSets(legoSets, "Just make it so it looks like a car.", 3);
smallCar.setManual(new Manual("One last attempt: Just build a car! Ok?", "Jens Schauder"));
repository.save(smallCar);
Output.list(repository.findAll(), "Manual replaced");
legoSets = repository.findAll();
Output.list(legoSets, "Manual replaced");
checkLegoSets(legoSets, "One last attempt: Just build a car! Ok?", 3);
}
private LegoSet createLegoSet() {
@Test
public void customQueries() {
LegoSet smallCars = createLegoSet("Small Car - 01", 5, 10);
smallCars.setManual(new Manual("Just put all the pieces together in the right order", "Jens Schauder"));
smallCars.addModel("SUV", "SUV with sliding doors.");
smallCars.addModel("roadster", "Slick red roadster.");
LegoSet f1Racer = createLegoSet("F1 Racer", 6, 15);
f1Racer.setManual(new Manual("Build a helicopter or a plane", "M. Shoemaker"));
f1Racer.addModel("F1 Ferrari 2018", "A very fast red car.");
LegoSet constructionVehicles = createLegoSet("Construction Vehicles", 3, 6);
constructionVehicles.setManual(
new Manual("Build a Road Roler, a Mobile Crane, a Tracked Dumper, or a Backhoe Loader ", "Bob the Builder"));
constructionVehicles.addModel("scoop", "A backhoe loader");
constructionVehicles.addModel("Muck", "Muck is a continuous tracked dump truck with an added bulldozer blade");
constructionVehicles.addModel("lofty", "A mobile crane");
constructionVehicles.addModel("roley",
"A road roller that loves to make up songs and frequently spins his eyes when he is excited.");
repository.saveAll(Arrays.asList(smallCars, f1Racer, constructionVehicles));
List<ModelReport> report = repository.reportModelForAge(6);
Output.list(report, "Model Report");
assertThat(report).hasSize(7)
.allMatch(m -> m.getDescription() != null && m.getModelName() != null && m.getSetName() != null);
int updated = repository.lowerCaseMapKeys();
// SUV, F1 Ferrari 2018 and Muck get updated
assertThat(updated).isEqualTo(3);
}
private LegoSet createLegoSet(String name, int minimumAge, int maximumAge) {
LegoSet smallCar = new LegoSet();
smallCar.setName("Small Car 01");
smallCar.setMinimumAge(Period.ofYears(5));
smallCar.setMaximumAge(Period.ofYears(12));
smallCar.setName(name);
smallCar.setMinimumAge(Period.ofYears(minimumAge));
smallCar.setMaximumAge(Period.ofYears(maximumAge));
return smallCar;
}
private void checkLegoSets(Iterable<LegoSet> legoSets, String manualText, int numberOfModels) {
assertThat(legoSets) //
.extracting( //
ls -> ls.getManual().getText(), //
ls -> ls.getModels().size()) //
.containsExactly(new Tuple(manualText, numberOfModels));
}
}