Browse Source
If a parent DbAction does not offer a generated id, the id of the entity is used instead. This behavior was broken by DATAJDBC-241. Related tickets: DATAJDBC-241. Original pull request: #85.pull/87/head
4 changed files with 292 additions and 7 deletions
@ -0,0 +1,253 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017-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 org.springframework.data.jdbc.repository; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*; |
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.RequiredArgsConstructor; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||||
|
import java.util.concurrent.atomic.AtomicLong; |
||||||
|
|
||||||
|
import org.junit.ClassRule; |
||||||
|
import org.junit.Rule; |
||||||
|
import org.junit.Test; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.context.ApplicationListener; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.context.annotation.Import; |
||||||
|
import org.springframework.data.annotation.Id; |
||||||
|
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; |
||||||
|
import org.springframework.data.jdbc.testing.TestConfiguration; |
||||||
|
import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent; |
||||||
|
import org.springframework.data.repository.CrudRepository; |
||||||
|
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; |
||||||
|
import org.springframework.test.context.ContextConfiguration; |
||||||
|
import org.springframework.test.context.junit4.rules.SpringClassRule; |
||||||
|
import org.springframework.test.context.junit4.rules.SpringMethodRule; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
/** |
||||||
|
* Very simple use cases for creation and usage of JdbcRepositories. |
||||||
|
* |
||||||
|
* @author Jens Schauder |
||||||
|
*/ |
||||||
|
@ContextConfiguration |
||||||
|
@Transactional |
||||||
|
public class JdbcRepositoryWithCollectionsAndManuallyAssignedIdHsqlIntegrationTests { |
||||||
|
|
||||||
|
static AtomicLong id = new AtomicLong(0); |
||||||
|
|
||||||
|
@Configuration |
||||||
|
@Import(TestConfiguration.class) |
||||||
|
static class Config { |
||||||
|
|
||||||
|
@Autowired JdbcRepositoryFactory factory; |
||||||
|
|
||||||
|
@Bean |
||||||
|
Class<?> testClass() { |
||||||
|
return JdbcRepositoryWithCollectionsAndManuallyAssignedIdHsqlIntegrationTests.class; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
DummyEntityRepository dummyEntityRepository() { |
||||||
|
return factory.getRepository(DummyEntityRepository.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public ApplicationListener<?> idSetting() { |
||||||
|
|
||||||
|
return (ApplicationListener<BeforeSaveEvent>) event -> { |
||||||
|
|
||||||
|
if (event.getEntity() instanceof DummyEntity) { |
||||||
|
setIds((DummyEntity) event.getEntity()); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
private void setIds(DummyEntity dummyEntity) { |
||||||
|
|
||||||
|
if (dummyEntity.getId() == null) { |
||||||
|
dummyEntity.setId(id.incrementAndGet()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@ClassRule public static final SpringClassRule classRule = new SpringClassRule(); |
||||||
|
@Rule public SpringMethodRule methodRule = new SpringMethodRule(); |
||||||
|
|
||||||
|
@Autowired NamedParameterJdbcTemplate template; |
||||||
|
@Autowired DummyEntityRepository repository; |
||||||
|
|
||||||
|
@Test // DATAJDBC-113
|
||||||
|
public void saveAndLoadEmptySet() { |
||||||
|
|
||||||
|
DummyEntity entity = repository.save(createDummyEntity()); |
||||||
|
|
||||||
|
assertThat(entity.id).isNotNull(); |
||||||
|
|
||||||
|
DummyEntity reloaded = repository.findById(entity.id).orElseThrow(AssertionFailedError::new); |
||||||
|
|
||||||
|
assertThat(reloaded.content) //
|
||||||
|
.isNotNull() //
|
||||||
|
.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAJDBC-113
|
||||||
|
public void saveAndLoadNonEmptySet() { |
||||||
|
|
||||||
|
Element element1 = new Element(); |
||||||
|
Element element2 = new Element(); |
||||||
|
|
||||||
|
DummyEntity entity = createDummyEntity(); |
||||||
|
entity.content.add(element1); |
||||||
|
entity.content.add(element2); |
||||||
|
|
||||||
|
entity = repository.save(entity); |
||||||
|
|
||||||
|
assertThat(entity.id).isNotNull(); |
||||||
|
assertThat(entity.content).allMatch(element -> element.id != null); |
||||||
|
|
||||||
|
DummyEntity reloaded = repository.findById(entity.id).orElseThrow(AssertionFailedError::new); |
||||||
|
|
||||||
|
assertThat(reloaded.content) //
|
||||||
|
.isNotNull() //
|
||||||
|
.extracting(e -> e.id) //
|
||||||
|
.containsExactlyInAnyOrder(element1.id, element2.id); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAJDBC-113
|
||||||
|
public void findAllLoadsCollection() { |
||||||
|
|
||||||
|
Element element1 = new Element(); |
||||||
|
Element element2 = new Element(); |
||||||
|
|
||||||
|
DummyEntity entity = createDummyEntity(); |
||||||
|
entity.content.add(element1); |
||||||
|
entity.content.add(element2); |
||||||
|
|
||||||
|
entity = repository.save(entity); |
||||||
|
|
||||||
|
assertThat(entity.id).isNotNull(); |
||||||
|
assertThat(entity.content).allMatch(element -> element.id != null); |
||||||
|
|
||||||
|
Iterable<DummyEntity> reloaded = repository.findAll(); |
||||||
|
|
||||||
|
assertThat(reloaded) //
|
||||||
|
.extracting(e -> e.id, e -> e.content.size()) //
|
||||||
|
.containsExactly(tuple(entity.id, entity.content.size())); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAJDBC-113
|
||||||
|
public void updateSet() { |
||||||
|
|
||||||
|
Element element1 = createElement("one"); |
||||||
|
Element element2 = createElement("two"); |
||||||
|
Element element3 = createElement("three"); |
||||||
|
|
||||||
|
DummyEntity entity = createDummyEntity(); |
||||||
|
entity.content.add(element1); |
||||||
|
entity.content.add(element2); |
||||||
|
|
||||||
|
entity = repository.save(entity); |
||||||
|
|
||||||
|
entity.content.remove(element1); |
||||||
|
element2.content = "two changed"; |
||||||
|
entity.content.add(element3); |
||||||
|
|
||||||
|
entity = repository.save(entity); |
||||||
|
|
||||||
|
assertThat(entity.id).isNotNull(); |
||||||
|
assertThat(entity.content).allMatch(element -> element.id != null); |
||||||
|
|
||||||
|
DummyEntity reloaded = repository.findById(entity.id).orElseThrow(AssertionFailedError::new); |
||||||
|
|
||||||
|
// the elements got properly updated and reloaded
|
||||||
|
assertThat(reloaded.content) //
|
||||||
|
.isNotNull() //
|
||||||
|
.extracting(e -> e.id, e -> e.content) //
|
||||||
|
.containsExactlyInAnyOrder( //
|
||||||
|
tuple(element2.id, "two changed"), //
|
||||||
|
tuple(element3.id, "three") //
|
||||||
|
); |
||||||
|
|
||||||
|
Long count = template.queryForObject("select count(1) from Element", new HashMap<>(), Long.class); |
||||||
|
assertThat(count).isEqualTo(2); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAJDBC-113
|
||||||
|
public void deletingWithSet() { |
||||||
|
|
||||||
|
Element element1 = createElement("one"); |
||||||
|
Element element2 = createElement("two"); |
||||||
|
|
||||||
|
DummyEntity entity = createDummyEntity(); |
||||||
|
entity.content.add(element1); |
||||||
|
entity.content.add(element2); |
||||||
|
|
||||||
|
entity = repository.save(entity); |
||||||
|
|
||||||
|
repository.deleteById(entity.id); |
||||||
|
|
||||||
|
assertThat(repository.findById(entity.id)).isEmpty(); |
||||||
|
|
||||||
|
Long count = template.queryForObject("select count(1) from Element", new HashMap<>(), Long.class); |
||||||
|
assertThat(count).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private Element createElement(String content) { |
||||||
|
|
||||||
|
Element element = new Element(); |
||||||
|
element.content = content; |
||||||
|
return element; |
||||||
|
} |
||||||
|
|
||||||
|
private static DummyEntity createDummyEntity() { |
||||||
|
|
||||||
|
DummyEntity entity = new DummyEntity(); |
||||||
|
entity.setName("Entity Name"); |
||||||
|
return entity; |
||||||
|
} |
||||||
|
|
||||||
|
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {} |
||||||
|
|
||||||
|
@Data |
||||||
|
static class DummyEntity { |
||||||
|
|
||||||
|
@Id private Long id; |
||||||
|
String name; |
||||||
|
Set<Element> content = new HashSet<>(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@RequiredArgsConstructor |
||||||
|
static class Element { |
||||||
|
|
||||||
|
@Id private Long id; |
||||||
|
String content; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
CREATE TABLE dummy_entity ( id BIGINT PRIMARY KEY, NAME VARCHAR(100)); |
||||||
|
CREATE TABLE element (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, content VARCHAR(100), dummy_entity BIGINT not null); |
||||||
Loading…
Reference in new issue