DATAJDBC-111 - Polishing.

Formatting.
Removed some redundant tests.
Some code simplifications.

Original pull request: #110.
This commit is contained in:
Jens Schauder
2019-01-24 11:25:38 +01:00
parent 7a26385b5a
commit 13cc4f6dd6
29 changed files with 228 additions and 730 deletions

View File

@@ -293,11 +293,13 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
}
if(property.isEmbedded()){
T value = (T) propertyAccessor.getProperty(property);
final RelationalPersistentEntity<T> embeddedEntity = (RelationalPersistentEntity<T>) context.getPersistentEntity(property.getType());
final MapSqlParameterSource additionalParameters = getPropertyMap(value, embeddedEntity, prefix + property.getEmbeddedPrefix());
Object value = propertyAccessor.getProperty(property);
final RelationalPersistentEntity<?> embeddedEntity = context.getPersistentEntity(property.getType());
final MapSqlParameterSource additionalParameters = getPropertyMap((T)value, (RelationalPersistentEntity<T>) embeddedEntity, prefix + property.getEmbeddedPrefix());
parameters.addValues(additionalParameters.getValues());
} else {
Object value = propertyAccessor.getProperty(property);
Object convertedValue = converter.writeValue(value, ClassTypeInformation.from(property.getColumnType()));
parameters.addValue(prefix + property.getColumnName(), convertedValue, JdbcUtil.sqlTypeFor(property.getColumnType()));

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.data.relational.core.conversion.RelationalConverter;
@@ -113,7 +114,7 @@ public class EntityRowMapper<T> implements RowMapper<T> {
return accessStrategy.findAllByProperty(id, property);
} else if (property.isMap() && id != null) {
return ITERABLE_OF_ENTRY_TO_MAP_CONVERTER.convert(accessStrategy.findAllByProperty(id, property));
} else if(property.isEmbedded()) {
} else if (property.isEmbedded()) {
return readEmbeddedEntityFrom(resultSet, id, property, prefix);
} else {
return readFrom(resultSet, property, prefix);
@@ -130,8 +131,9 @@ public class EntityRowMapper<T> implements RowMapper<T> {
*/
@Nullable
private Object readFrom(ResultSet resultSet, RelationalPersistentProperty property, String prefix) {
if (property.isEntity()) {
return readEntityFrom(resultSet, property, prefix);
return readEntityFrom(resultSet, property, prefix);
}
Object value = getObjectFromResultSet(resultSet, prefix + property.getColumnName());
@@ -139,17 +141,18 @@ public class EntityRowMapper<T> implements RowMapper<T> {
}
@Nullable
private <S> S readEmbeddedEntityFrom(ResultSet rs, @Nullable Object id, RelationalPersistentProperty property, String prefix) {
private Object readEmbeddedEntityFrom(ResultSet rs, @Nullable Object id, RelationalPersistentProperty property,
String prefix) {
String newPrefix = prefix + property.getEmbeddedPrefix();
RelationalPersistentEntity<?> entity = context.getRequiredPersistentEntity(property.getActualType());
Object instance = createInstance(entity, rs, null, newPrefix);
@SuppressWarnings("unchecked")
RelationalPersistentEntity<S> entity = (RelationalPersistentEntity<S>) context
.getRequiredPersistentEntity(property.getActualType());
S instance = createInstance(entity, rs, null, newPrefix);
PersistentPropertyAccessor<S> accessor = converter.getPropertyAccessor(entity, instance);
PersistentPropertyAccessor<?> accessor = converter.getPropertyAccessor((PersistentEntity<Object, ?>) entity,
instance);
for (RelationalPersistentProperty p : entity) {
accessor.setProperty(p, readOrLoadProperty(rs, id, p, newPrefix));

View File

@@ -72,7 +72,9 @@ class SqlGenerator {
}
private void initColumnNames(RelationalPersistentEntity<?> entity, String prefix) {
entity.doWithProperties((PropertyHandler<RelationalPersistentProperty>) property -> {
// the referencing column of referenced entity is expected to be on the other side of the relation
if (!property.isEntity()) {
initSimpleColumnName(property, prefix);
@@ -83,16 +85,21 @@ class SqlGenerator {
}
private void initSimpleColumnName(RelationalPersistentProperty property, String prefix) {
String columnName = prefix + property.getColumnName();
columnNames.add(columnName);
if (!entity.isIdProperty(property)) {
nonIdColumnNames.add(columnName);
}
}
private void initEmbeddedColumnNames(RelationalPersistentProperty property, String prefix) {
final String embeddedPrefix = property.getEmbeddedPrefix();
final RelationalPersistentEntity<?> embeddedEntity = context.getPersistentEntity(property.getColumnType());
final RelationalPersistentEntity<?> embeddedEntity = context.getRequiredPersistentEntity(property.getColumnType());
initColumnNames(embeddedEntity, prefix + embeddedPrefix);
}
@@ -189,10 +196,10 @@ class SqlGenerator {
}
/**
* Adds the columns to the provided {@link SelectBuilder} representing simplem properties, including those from
* Adds the columns to the provided {@link SelectBuilder} representing simple properties, including those from
* one-to-one relationships.
*
* @param rootEntity
* @param rootEntity the root entity for which to add the columns.
* @param builder The {@link SelectBuilder} to be modified.
*/
private void addColumnsAndJoinsForOneToOneReferences(RelationalPersistentEntity<?> entity, String prefix,
@@ -356,8 +363,6 @@ class SqlGenerator {
RelationalPersistentEntity<?> entityToDelete = context
.getRequiredPersistentEntity(path.getRequiredLeafProperty().getActualType());
RelationalPersistentProperty property = path.getBaseProperty();
final String innerMostCondition1 = createInnerMostCondition("%s IS NOT NULL", path);
String condition = cascadeConditions(innerMostCondition1, getSubPath(path));
@@ -381,7 +386,8 @@ class SqlGenerator {
private String createInnerMostCondition(String template, PersistentPropertyPath<RelationalPersistentProperty> path) {
PersistentPropertyPath<RelationalPersistentProperty> currentPath = path;
while (!currentPath.getParentPath().isEmpty() && !currentPath.getParentPath().getRequiredLeafProperty().isEmbedded()){
while (!currentPath.getParentPath().isEmpty()
&& !currentPath.getParentPath().getRequiredLeafProperty().isEmbedded()) {
currentPath = currentPath.getParentPath();
}
@@ -408,9 +414,7 @@ class SqlGenerator {
ancestor = ancestor.getParentPath();
}
final PersistentPropertyPath<RelationalPersistentProperty> extensionForBaseOf = path
.getExtensionForBaseOf(ancestor);
return extensionForBaseOf;
return path.getExtensionForBaseOf(ancestor);
}
private String cascadeConditions(String innerCondition, PersistentPropertyPath<RelationalPersistentProperty> path) {

View File

@@ -149,6 +149,7 @@ public class EntityRowMapperUnitTests {
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta");
}
// TODO add additional test for multilevel embeddables
@Test // DATAJDBC-111
public void simpleEmbeddedGetsProperlyExtracted() throws SQLException {

View File

@@ -1,188 +0,0 @@
/*
* Copyright 2017-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
*
* 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.core;
import static java.util.Collections.*;
import org.assertj.core.api.SoftAssertions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Embedded;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
/**
* Unit tests for the {@link SqlGenerator} in a context of the {@link Embedded} annotation.
*
* @author Bastian Wilhelm
*/
public class SqlGeneratorEmbeddedCascadingUnitTests {
private SqlGenerator sqlGenerator;
@Before
public void setUp() {
this.sqlGenerator = createSqlGenerator(DummyEntity.class);
}
SqlGenerator createSqlGenerator(Class<?> type) {
RelationalMappingContext context = new JdbcMappingContext();
RelationalPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(type);
return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
}
@Test // DATAJDBC-111
public void findOne() {
final String sql = sqlGenerator.getFindOne();
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(sql)
.startsWith("SELECT")
.contains("dummy_entity.id1 AS id1")
.contains("dummy_entity.test AS test")
.contains("dummy_entity.attr1 AS attr1")
.contains("dummy_entity.attr2 AS attr2")
.contains("dummy_entity.prefix2_attr1 AS prefix2_attr1")
.contains("dummy_entity.prefix2_attr2 AS prefix2_attr2")
.contains("dummy_entity.prefix_test AS prefix_test")
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
.contains("dummy_entity.prefix_attr2 AS prefix_attr2")
.contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1")
.contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2")
.contains("WHERE dummy_entity.id1 = :id")
.doesNotContain("JOIN").doesNotContain("embeddable");
softAssertions.assertAll();
}
@Test // DATAJDBC-111
public void findAll() {
final String sql = sqlGenerator.getFindAll();
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(sql)
.startsWith("SELECT")
.contains("dummy_entity.id1 AS id1")
.contains("dummy_entity.test AS test")
.contains("dummy_entity.attr1 AS attr1")
.contains("dummy_entity.attr2 AS attr2")
.contains("dummy_entity.prefix2_attr1 AS prefix2_attr1")
.contains("dummy_entity.prefix2_attr2 AS prefix2_attr2")
.contains("dummy_entity.prefix_test AS prefix_test")
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
.contains("dummy_entity.prefix_attr2 AS prefix_attr2")
.contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1")
.contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2")
.doesNotContain("JOIN").doesNotContain("embeddable");
softAssertions.assertAll();
}
@Test // DATAJDBC-111
public void findAllInList() {
final String sql = sqlGenerator.getFindAllInList();
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(sql)
.startsWith("SELECT")
.contains("dummy_entity.id1 AS id1")
.contains("dummy_entity.test AS test")
.contains("dummy_entity.attr1 AS attr1")
.contains("dummy_entity.attr2 AS attr2")
.contains("dummy_entity.prefix2_attr1 AS prefix2_attr1")
.contains("dummy_entity.prefix2_attr2 AS prefix2_attr2")
.contains("dummy_entity.prefix_test AS prefix_test")
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
.contains("dummy_entity.prefix_attr2 AS prefix_attr2")
.contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1")
.contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2")
.contains("WHERE dummy_entity.id1 in(:ids)")
.doesNotContain("JOIN").doesNotContain("embeddable");
softAssertions.assertAll();
}
@Test // DATAJDBC-111
public void insert() {
final String sql = sqlGenerator.getInsert(emptySet());
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(sql)
.startsWith("INSERT INTO")
.contains("dummy_entity")
.contains(":test")
.contains(":attr1")
.contains(":attr2")
.contains(":prefix2_attr1")
.contains(":prefix2_attr2")
.contains(":prefix_test")
.contains(":prefix_attr1")
.contains(":prefix_attr2")
.contains(":prefix_prefix2_attr1")
.contains(":prefix_prefix2_attr2");
softAssertions.assertAll();
}
@Test // DATAJDBC-111
public void update() {
final String sql = sqlGenerator.getUpdate();
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(sql)
.startsWith("UPDATE")
.contains("dummy_entity")
.contains("test = :test")
.contains("attr1 = :attr1")
.contains("attr2 = :attr2")
.contains("prefix2_attr1 = :prefix2_attr1")
.contains("prefix2_attr2 = :prefix2_attr2")
.contains("prefix_test = :prefix_test")
.contains("prefix_attr1 = :prefix_attr1")
.contains("prefix_attr2 = :prefix_attr2")
.contains("prefix_prefix2_attr1 = :prefix_prefix2_attr1")
.contains("prefix_prefix2_attr2 = :prefix_prefix2_attr2");
softAssertions.assertAll();
}
@SuppressWarnings("unused")
static class DummyEntity {
@Column("id1")
@Id
Long id;
@Embedded("prefix_")
CascadedEmbedded prefixedEmbeddable;
@Embedded
CascadedEmbedded embeddable;
}
@SuppressWarnings("unused")
static class CascadedEmbedded
{
String test;
@Embedded("prefix2_") Embeddable prefixedEmbeddable;
@Embedded Embeddable embeddable;
}
@SuppressWarnings("unused")
static class Embeddable
{
Long attr1;
String attr2;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 the original author or authors.
* Copyright 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.
@@ -15,22 +15,17 @@
*/
package org.springframework.data.jdbc.core;
import static java.util.Collections.*;
import org.assertj.core.api.SoftAssertions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Embedded;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for the {@link SqlGenerator} in a context of the {@link Embedded} annotation.
@@ -60,10 +55,16 @@ public class SqlGeneratorEmbeddedUnitTests {
softAssertions.assertThat(sql)
.startsWith("SELECT")
.contains("dummy_entity.id1 AS id1")
.contains("dummy_entity.test AS test")
.contains("dummy_entity.attr1 AS attr1")
.contains("dummy_entity.attr2 AS attr2")
.contains("dummy_entity.prefix2_attr1 AS prefix2_attr1")
.contains("dummy_entity.prefix2_attr2 AS prefix2_attr2")
.contains("dummy_entity.prefix_test AS prefix_test")
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
.contains("dummy_entity.prefix_attr2 AS prefix_attr2")
.contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1")
.contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2")
.contains("WHERE dummy_entity.id1 = :id")
.doesNotContain("JOIN").doesNotContain("embeddable");
softAssertions.assertAll();
@@ -77,10 +78,16 @@ public class SqlGeneratorEmbeddedUnitTests {
softAssertions.assertThat(sql)
.startsWith("SELECT")
.contains("dummy_entity.id1 AS id1")
.contains("dummy_entity.test AS test")
.contains("dummy_entity.attr1 AS attr1")
.contains("dummy_entity.attr2 AS attr2")
.contains("dummy_entity.prefix2_attr1 AS prefix2_attr1")
.contains("dummy_entity.prefix2_attr2 AS prefix2_attr2")
.contains("dummy_entity.prefix_test AS prefix_test")
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
.contains("dummy_entity.prefix_attr2 AS prefix_attr2")
.contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1")
.contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2")
.doesNotContain("JOIN").doesNotContain("embeddable");
softAssertions.assertAll();
}
@@ -93,10 +100,16 @@ public class SqlGeneratorEmbeddedUnitTests {
softAssertions.assertThat(sql)
.startsWith("SELECT")
.contains("dummy_entity.id1 AS id1")
.contains("dummy_entity.test AS test")
.contains("dummy_entity.attr1 AS attr1")
.contains("dummy_entity.attr2 AS attr2")
.contains("dummy_entity.prefix2_attr1 AS prefix2_attr1")
.contains("dummy_entity.prefix2_attr2 AS prefix2_attr2")
.contains("dummy_entity.prefix_test AS prefix_test")
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
.contains("dummy_entity.prefix_attr2 AS prefix_attr2")
.contains("dummy_entity.prefix_prefix2_attr1 AS prefix_prefix2_attr1")
.contains("dummy_entity.prefix_prefix2_attr2 AS prefix_prefix2_attr2")
.contains("WHERE dummy_entity.id1 in(:ids)")
.doesNotContain("JOIN").doesNotContain("embeddable");
softAssertions.assertAll();
@@ -110,10 +123,16 @@ public class SqlGeneratorEmbeddedUnitTests {
softAssertions.assertThat(sql)
.startsWith("INSERT INTO")
.contains("dummy_entity")
.contains(":test")
.contains(":attr1")
.contains(":attr2")
.contains(":prefix2_attr1")
.contains(":prefix2_attr2")
.contains(":prefix_test")
.contains(":prefix_attr1")
.contains(":prefix_attr2");
.contains(":prefix_attr2")
.contains(":prefix_prefix2_attr1")
.contains(":prefix_prefix2_attr2");
softAssertions.assertAll();
}
@@ -125,10 +144,16 @@ public class SqlGeneratorEmbeddedUnitTests {
softAssertions.assertThat(sql)
.startsWith("UPDATE")
.contains("dummy_entity")
.contains("test = :test")
.contains("attr1 = :attr1")
.contains("attr2 = :attr2")
.contains("prefix2_attr1 = :prefix2_attr1")
.contains("prefix2_attr2 = :prefix2_attr2")
.contains("prefix_test = :prefix_test")
.contains("prefix_attr1 = :prefix_attr1")
.contains("prefix_attr2 = :prefix_attr2");
.contains("prefix_attr2 = :prefix_attr2")
.contains("prefix_prefix2_attr1 = :prefix_prefix2_attr1")
.contains("prefix_prefix2_attr2 = :prefix_prefix2_attr2");
softAssertions.assertAll();
}
@@ -140,10 +165,18 @@ public class SqlGeneratorEmbeddedUnitTests {
Long id;
@Embedded("prefix_")
Embeddable prefixedEmbeddable;
CascadedEmbedded prefixedEmbeddable;
@Embedded
Embeddable embeddable;
CascadedEmbedded embeddable;
}
@SuppressWarnings("unused")
static class CascadedEmbedded
{
String test;
@Embedded("prefix2_") Embeddable prefixedEmbeddable;
@Embedded Embeddable embeddable;
}
@SuppressWarnings("unused")

View File

@@ -1,262 +0,0 @@
/*
* Copyright 2017-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
*
* 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 java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
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.Embedded;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
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.test.jdbc.JdbcTestUtils;
import org.springframework.transaction.annotation.Transactional;
/**
* Very simple use cases for creation and usage of JdbcRepositories with test {@link Embedded} annotation in Entities.
*
* @author Bastian Wilhelm
*/
@ContextConfiguration
@Transactional
public class JdbcRepositoryEmbeddedCascadingIntegrationTests {
@Configuration
@Import(TestConfiguration.class)
static class Config {
@Autowired JdbcRepositoryFactory factory;
@Bean
Class<?> testClass() {
return JdbcRepositoryEmbeddedCascadingIntegrationTests.class;
}
@Bean
DummyEntityRepository dummyEntityRepository() {
return factory.getRepository(DummyEntityRepository.class);
}
}
@ClassRule public static final SpringClassRule classRule = new SpringClassRule();
@Rule public SpringMethodRule methodRule = new SpringMethodRule();
@Autowired NamedParameterJdbcTemplate template;
@Autowired DummyEntityRepository repository;
@Test // DATAJDBC-111
public void savesAnEntity() {
DummyEntity entity = repository.save(createDummyEntity());
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id = " + entity.getId())).isEqualTo(1);
}
@Test // DATAJDBC-111
public void saveAndLoadAnEntity() {
DummyEntity entity = repository.save(createDummyEntity());
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
assertThat(it.getId()).isEqualTo(entity.getId());
assertThat(it.getPrefixedEmbeddable().getTest()).isEqualTo(entity.getPrefixedEmbeddable().getTest());
assertThat(it.getPrefixedEmbeddable().getEmbeddable().getAttr()).isEqualTo(entity.getPrefixedEmbeddable().getEmbeddable().getAttr());
assertThat(it.getEmbeddable().getTest()).isEqualTo(entity.getEmbeddable().getTest());
assertThat(it.getEmbeddable().getEmbeddable().getAttr()).isEqualTo(entity.getEmbeddable().getEmbeddable().getAttr());
});
}
@Test // DATAJDBC-111
public void findAllFindsAllEntities() {
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
Iterable<DummyEntity> all = repository.findAll();
assertThat(all)//
.extracting(DummyEntity::getId)//
.containsExactlyInAnyOrder(entity.getId(), other.getId());
}
@Test // DATAJDBC-111
public void findByIdReturnsEmptyWhenNoneFound() {
// NOT saving anything, so DB is empty
assertThat(repository.findById(-1L)).isEmpty();
}
@Test // DATAJDBC-111
public void update() {
DummyEntity entity = repository.save(createDummyEntity());
entity.getPrefixedEmbeddable().setTest("something else");
entity.getPrefixedEmbeddable().getEmbeddable().setAttr(3L);
DummyEntity saved = repository.save(entity);
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
assertThat(it.getPrefixedEmbeddable().getTest()).isEqualTo(saved.getPrefixedEmbeddable().getTest());
assertThat(it.getPrefixedEmbeddable().getEmbeddable().getAttr()).isEqualTo(saved.getPrefixedEmbeddable().getEmbeddable().getAttr());
});
}
@Test // DATAJDBC-111
public void updateMany() {
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
entity.getEmbeddable().setTest("something else");
other.getEmbeddable().setTest("others Name");
entity.getPrefixedEmbeddable().getEmbeddable().setAttr(3L);
other.getPrefixedEmbeddable().getEmbeddable().setAttr(5L);
repository.saveAll(asList(entity, other));
assertThat(repository.findAll()) //
.extracting(d -> d.getEmbeddable().getTest()) //
.containsExactlyInAnyOrder(entity.getEmbeddable().getTest(), other.getEmbeddable().getTest());
assertThat(repository.findAll()) //
.extracting(d -> d.getPrefixedEmbeddable().getEmbeddable().getAttr()) //
.containsExactlyInAnyOrder(entity.getPrefixedEmbeddable().getEmbeddable().getAttr(), other.getPrefixedEmbeddable().getEmbeddable().getAttr());
}
@Test // DATAJDBC-111
public void deleteById() {
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
repository.deleteById(two.getId());
assertThat(repository.findAll()) //
.extracting(DummyEntity::getId) //
.containsExactlyInAnyOrder(one.getId(), three.getId());
}
@Test // DATAJDBC-111
public void deleteByEntity() {
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
repository.delete(one);
assertThat(repository.findAll()) //
.extracting(DummyEntity::getId) //
.containsExactlyInAnyOrder(two.getId(), three.getId());
}
@Test // DATAJDBC-111
public void deleteByList() {
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
repository.deleteAll(asList(one, three));
assertThat(repository.findAll()) //
.extracting(DummyEntity::getId) //
.containsExactlyInAnyOrder(two.getId());
}
@Test // DATAJDBC-111
public void deleteAll() {
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.save(createDummyEntity());
assertThat(repository.findAll()).isNotEmpty();
repository.deleteAll();
assertThat(repository.findAll()).isEmpty();
}
private static DummyEntity createDummyEntity() {
DummyEntity entity = new DummyEntity();
final CascadedEmbeddable prefixedCascadedEmbeddable = new CascadedEmbeddable();
prefixedCascadedEmbeddable.setTest("c1");
final Embeddable embeddable1 = new Embeddable();
embeddable1.setAttr(1L);
prefixedCascadedEmbeddable.setEmbeddable(embeddable1);
entity.setPrefixedEmbeddable(prefixedCascadedEmbeddable);
final CascadedEmbeddable cascadedEmbeddable = new CascadedEmbeddable();
cascadedEmbeddable.setTest("c2");
final Embeddable embeddable2 = new Embeddable();
embeddable2.setAttr(2L);
cascadedEmbeddable.setEmbeddable(embeddable2);
entity.setEmbeddable(cascadedEmbeddable);
return entity;
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
@Data
static class DummyEntity {
@Id Long id;
@Embedded("prefix_") CascadedEmbeddable prefixedEmbeddable;
@Embedded CascadedEmbeddable embeddable;
}
@Data
static class CascadedEmbeddable {
String test;
@Embedded("prefix2_")
Embeddable embeddable;
}
@Data
static class Embeddable {
Long attr;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 the original author or authors.
* Copyright 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.
@@ -75,15 +75,6 @@ public class JdbcRepositoryEmbeddedImmutableIntegrationTests {
@Autowired NamedParameterJdbcTemplate template;
@Autowired DummyEntityRepository repository;
@Test // DATAJDBC-111
public void savesAnEntity() {
DummyEntity entity = repository.save(createDummyEntity());
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id = " + entity.getId())).isEqualTo(1);
}
@Test // DATAJDBC-111
public void saveAndLoadAnEntity() {
@@ -96,121 +87,14 @@ public class JdbcRepositoryEmbeddedImmutableIntegrationTests {
});
}
@Test // DATAJDBC-111
public void findAllFindsAllEntities() {
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
Iterable<DummyEntity> all = repository.findAll();
assertThat(all)//
.extracting(DummyEntity::getId)//
.containsExactlyInAnyOrder(entity.getId(), other.getId());
}
@Test // DATAJDBC-111
public void findByIdReturnsEmptyWhenNoneFound() {
// NOT saving anything, so DB is empty
assertThat(repository.findById(-1L)).isEmpty();
}
@Test // DATAJDBC-111
public void update() {
DummyEntity entity = repository.save(createDummyEntity());
entity.setPrefixedEmbeddable(entity.getPrefixedEmbeddable().withAttr2("something else"));
DummyEntity saved = repository.save(entity);
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
assertThat(it.getPrefixedEmbeddable().getAttr2()).isEqualTo(saved.getPrefixedEmbeddable().getAttr2());
});
}
@Test // DATAJDBC-111
public void updateMany() {
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
entity.setPrefixedEmbeddable(entity.getPrefixedEmbeddable().withAttr2("something else"));
other.setPrefixedEmbeddable(entity.getPrefixedEmbeddable().withAttr2("others Name"));
repository.saveAll(asList(entity, other));
assertThat(repository.findAll()) //
.extracting(d -> d.getPrefixedEmbeddable().getAttr2()) //
.containsExactlyInAnyOrder(entity.getPrefixedEmbeddable().getAttr2(), other.getPrefixedEmbeddable().getAttr2());
}
@Test // DATAJDBC-111
public void deleteById() {
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
repository.deleteById(two.getId());
assertThat(repository.findAll()) //
.extracting(DummyEntity::getId) //
.containsExactlyInAnyOrder(one.getId(), three.getId());
}
@Test // DATAJDBC-111
public void deleteByEntity() {
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
repository.delete(one);
assertThat(repository.findAll()) //
.extracting(DummyEntity::getId) //
.containsExactlyInAnyOrder(two.getId(), three.getId());
}
@Test // DATAJDBC-111
public void deleteByList() {
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
repository.deleteAll(asList(one, three));
assertThat(repository.findAll()) //
.extracting(DummyEntity::getId) //
.containsExactlyInAnyOrder(two.getId());
}
@Test // DATAJDBC-111
public void deleteAll() {
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.save(createDummyEntity());
assertThat(repository.findAll()).isNotEmpty();
repository.deleteAll();
assertThat(repository.findAll()).isEmpty();
}
private static DummyEntity createDummyEntity() {
DummyEntity entity = new DummyEntity();
entity.setPrefixedEmbeddable(new Embeddable(1L, "test1"));
return entity;
return new DummyEntity(null, new Embeddable(1L, "test1"));
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
@Data
@Value
@Wither
static class DummyEntity {
@Id Long id;
@@ -221,6 +105,7 @@ public class JdbcRepositoryEmbeddedImmutableIntegrationTests {
@Value
@Wither
private static class Embeddable {
Long attr1;
String attr2;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 the original author or authors.
* Copyright 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.
@@ -41,7 +41,7 @@ import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.transaction.annotation.Transactional;
/**
* Very simple use cases for creation and usage of JdbcRepositories with {@link Embedded} annotation in Entities.
* Very simple use cases for creation and usage of JdbcRepositories with test {@link Embedded} annotation in Entities.
*
* @author Bastian Wilhelm
*/
@@ -89,10 +89,10 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
assertThat(it.getId()).isEqualTo(entity.getId());
assertThat(it.getPrefixedEmbeddable().getAttr1()).isEqualTo(entity.getPrefixedEmbeddable().getAttr1());
assertThat(it.getPrefixedEmbeddable().getAttr2()).isEqualTo(entity.getPrefixedEmbeddable().getAttr2());
assertThat(it.getEmbeddable().getAttr1()).isEqualTo(entity.getEmbeddable().getAttr1());
assertThat(it.getEmbeddable().getAttr2()).isEqualTo(entity.getEmbeddable().getAttr2());
assertThat(it.getPrefixedEmbeddable().getTest()).isEqualTo(entity.getPrefixedEmbeddable().getTest());
assertThat(it.getPrefixedEmbeddable().getEmbeddable().getAttr()).isEqualTo(entity.getPrefixedEmbeddable().getEmbeddable().getAttr());
assertThat(it.getEmbeddable().getTest()).isEqualTo(entity.getEmbeddable().getTest());
assertThat(it.getEmbeddable().getEmbeddable().getAttr()).isEqualTo(entity.getEmbeddable().getEmbeddable().getAttr());
});
}
@@ -121,11 +121,13 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
DummyEntity entity = repository.save(createDummyEntity());
entity.getPrefixedEmbeddable().setAttr2("something else");
entity.getPrefixedEmbeddable().setTest("something else");
entity.getPrefixedEmbeddable().getEmbeddable().setAttr(3L);
DummyEntity saved = repository.save(entity);
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
assertThat(it.getPrefixedEmbeddable().getAttr2()).isEqualTo(saved.getPrefixedEmbeddable().getAttr2());
assertThat(it.getPrefixedEmbeddable().getTest()).isEqualTo(saved.getPrefixedEmbeddable().getTest());
assertThat(it.getPrefixedEmbeddable().getEmbeddable().getAttr()).isEqualTo(saved.getPrefixedEmbeddable().getEmbeddable().getAttr());
});
}
@@ -135,14 +137,21 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
entity.getEmbeddable().setAttr2("something else");
other.getEmbeddable().setAttr2("others Name");
entity.getEmbeddable().setTest("something else");
other.getEmbeddable().setTest("others Name");
entity.getPrefixedEmbeddable().getEmbeddable().setAttr(3L);
other.getPrefixedEmbeddable().getEmbeddable().setAttr(5L);
repository.saveAll(asList(entity, other));
assertThat(repository.findAll()) //
.extracting(d -> d.getEmbeddable().getAttr2()) //
.containsExactlyInAnyOrder(entity.getEmbeddable().getAttr2(), other.getEmbeddable().getAttr2());
.extracting(d -> d.getEmbeddable().getTest()) //
.containsExactlyInAnyOrder(entity.getEmbeddable().getTest(), other.getEmbeddable().getTest());
assertThat(repository.findAll()) //
.extracting(d -> d.getPrefixedEmbeddable().getEmbeddable().getAttr()) //
.containsExactlyInAnyOrder(entity.getPrefixedEmbeddable().getEmbeddable().getAttr(), other.getPrefixedEmbeddable().getEmbeddable().getAttr());
}
@Test // DATAJDBC-111
@@ -200,18 +209,28 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
assertThat(repository.findAll()).isEmpty();
}
private static DummyEntity createDummyEntity() {
DummyEntity entity = new DummyEntity();
final Embeddable prefixedEmbeddable = new Embeddable();
prefixedEmbeddable.setAttr1(1L);
prefixedEmbeddable.setAttr2("test1");
entity.setPrefixedEmbeddable(prefixedEmbeddable);
final CascadedEmbeddable prefixedCascadedEmbeddable = new CascadedEmbeddable();
prefixedCascadedEmbeddable.setTest("c1");
final Embeddable embeddable = new Embeddable();
embeddable.setAttr1(2L);
embeddable.setAttr2("test2");
entity.setEmbeddable(embeddable);
final Embeddable embeddable1 = new Embeddable();
embeddable1.setAttr(1L);
prefixedCascadedEmbeddable.setEmbeddable(embeddable1);
entity.setPrefixedEmbeddable(prefixedCascadedEmbeddable);
final CascadedEmbeddable cascadedEmbeddable = new CascadedEmbeddable();
cascadedEmbeddable.setTest("c2");
final Embeddable embeddable2 = new Embeddable();
embeddable2.setAttr(2L);
cascadedEmbeddable.setEmbeddable(embeddable2);
entity.setEmbeddable(cascadedEmbeddable);
return entity;
}
@@ -223,14 +242,21 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
@Id Long id;
@Embedded("prefix_") Embeddable prefixedEmbeddable;
@Embedded("prefix_") CascadedEmbeddable prefixedEmbeddable;
@Embedded Embeddable embeddable;
@Embedded CascadedEmbeddable embeddable;
}
@Data
static class CascadedEmbeddable {
String test;
@Embedded("prefix2_")
Embeddable embeddable;
}
@Data
static class Embeddable {
Long attr1;
String attr2;
Long attr;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 the original author or authors.
* Copyright 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 the original author or authors.
* Copyright 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 the original author or authors.
* Copyright 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.

View File

@@ -0,0 +1 @@
microsoft/mssql-server-linux:2017-CU6

View File

@@ -1 +0,0 @@
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT)

View File

@@ -1 +0,0 @@
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1,2 +0,0 @@
DROP TABLE IF EXISTS dummy_entity;
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1 +0,0 @@
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1,2 +0,0 @@
DROP TABLE dummy_entity;
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1 +1 @@
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100))
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT)

View File

@@ -1 +1 @@
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1,2 +1,2 @@
DROP TABLE IF EXISTS dummy_entity;
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1 +1 @@
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -1,2 +1,2 @@
DROP TABLE dummy_entity;
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);

View File

@@ -15,6 +15,13 @@
*/
package org.springframework.data.relational.core.conversion;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PersistentPropertyPaths;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
@@ -23,14 +30,6 @@ import org.springframework.data.util.Pair;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
* Holds context information for the current save operation.
*
@@ -121,18 +120,20 @@ class WritingContext {
List<DbAction<?>> actions = new ArrayList<>();
from(path).forEach(node -> {
DbAction.Insert<Object> insert;
if (node.getPath().getRequiredLeafProperty().isQualified()) {
Pair<Object, Object> value = (Pair) node.getValue();
insert = new DbAction.Insert<>(value.getSecond(), path, getAction(node.getParent()));
insert.getAdditionalValues().put(node.getPath().getRequiredLeafProperty().getKeyColumn(), value.getFirst());
DbAction.Insert<Object> insert;
if (node.getPath().getRequiredLeafProperty().isQualified()) {
} else {
insert = new DbAction.Insert<>(node.getValue(), path, getAction(node.getParent()));
}
previousActions.put(node, insert);
actions.add(insert);
@SuppressWarnings("unchecked")
Pair<Object, Object> value = (Pair) node.getValue();
insert = new DbAction.Insert<>(value.getSecond(), path, getAction(node.getParent()));
insert.getAdditionalValues().put(node.getPath().getRequiredLeafProperty().getKeyColumn(), value.getFirst());
} else {
insert = new DbAction.Insert<>(node.getValue(), path, getAction(node.getParent()));
}
previousActions.put(node, insert);
actions.add(insert);
});
return actions;
@@ -186,12 +187,11 @@ class WritingContext {
// return context.getRequiredPersistentEntity(o.getClass()).isNew(o);
// }
private List<PathNode> from(
PersistentPropertyPath<RelationalPersistentProperty> path) {
private List<PathNode> from(PersistentPropertyPath<RelationalPersistentProperty> path) {
List<PathNode> nodes = new ArrayList<>();
if (dependsOnRootIgnoringEmbeddables(path)) {
if (isDirectlyReferencedByRootIgnoringEmbeddables(path)) {
Object value = getFromRootValue(path);
nodes.addAll(createNodes(path, null, value));
@@ -213,11 +213,14 @@ class WritingContext {
return nodes;
}
private boolean dependsOnRootIgnoringEmbeddables(PersistentPropertyPath<RelationalPersistentProperty> path){
private boolean isDirectlyReferencedByRootIgnoringEmbeddables(
PersistentPropertyPath<RelationalPersistentProperty> path) {
PersistentPropertyPath<RelationalPersistentProperty> currentPath = path.getParentPath();
while (!currentPath.isEmpty()){
if(!currentPath.getRequiredLeafProperty().isEmbedded()){
while (!currentPath.isEmpty()) {
if (!currentPath.getRequiredLeafProperty().isEmbedded()) {
return false;
}
currentPath = currentPath.getParentPath();
@@ -227,32 +230,11 @@ class WritingContext {
}
@Nullable
private Object getFromRootValue(PersistentPropertyPath<RelationalPersistentProperty> path){
final Stack<PersistentPropertyPath<RelationalPersistentProperty>> stack = new Stack<>();
PersistentPropertyPath<RelationalPersistentProperty> currentPath = path;
while (!currentPath.isEmpty()){
stack.push(currentPath);
currentPath = currentPath.getParentPath();
}
Object value = entity;
while (!stack.empty() && value != null){
currentPath = stack.pop();
final RelationalPersistentProperty property = currentPath.getRequiredLeafProperty();
value = context //
.getRequiredPersistentEntity(property.getOwner().getType()) //
.getPropertyAccessor(value) //
.getProperty(property);
}
return value;
private Object getFromRootValue(PersistentPropertyPath<RelationalPersistentProperty> path) {
return path.getBaseProperty().getOwner().getPropertyAccessor(entity).getProperty(path);
}
private List<PathNode> createNodes(
PersistentPropertyPath<RelationalPersistentProperty> path,
private List<PathNode> createNodes(PersistentPropertyPath<RelationalPersistentProperty> path,
@Nullable PathNode parentNode, @Nullable Object value) {
if (value == null) {
@@ -260,13 +242,12 @@ class WritingContext {
}
List<PathNode> nodes = new ArrayList<>();
if(path.getRequiredLeafProperty().isEmbedded()){
if (path.getRequiredLeafProperty().isEmbedded()) {
nodes.add(new PathNode(path, parentNode, value));
} else if (path.getRequiredLeafProperty().isQualified()) {
if (path.getRequiredLeafProperty().isMap()) {
((Map<?, ?>) value)
.forEach((k, v) -> nodes.add(new PathNode(path, parentNode, Pair.of(k, v))));
((Map<?, ?>) value).forEach((k, v) -> nodes.add(new PathNode(path, parentNode, Pair.of(k, v))));
} else {
List listValue = (List) value;

View File

@@ -77,16 +77,11 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
this.context = context;
this.isEmbedded = Lazy.of(() -> Optional.ofNullable(
findAnnotation(Embedded.class))
.isPresent()
);
this.isEmbedded = Lazy.of(() -> Optional.ofNullable(findAnnotation(Embedded.class)).isPresent());
this.embeddedPrefix = Lazy.of(() -> Optional.ofNullable(
findAnnotation(Embedded.class))
.map(Embedded::value)
.orElse("")
);
this.embeddedPrefix = Lazy.of(() -> Optional.ofNullable(findAnnotation(Embedded.class)) //
.map(Embedded::value) //
.orElse(""));
this.columnName = Lazy.of(() -> Optional.ofNullable( //
findAnnotation(Column.class)) //
@@ -187,16 +182,12 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
return isEmbedded.get();
}
@Override
public String getEmbeddedPrefix() {
if(isEmbedded()){
return embeddedPrefix.get();
} else {
return null;
}
}
@Override
public String getEmbeddedPrefix() {
return isEmbedded() ? embeddedPrefix.get() : null;
}
private boolean isListLike() {
private boolean isListLike() {
return isCollectionLike() && !Set.class.isAssignableFrom(this.getType());
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright 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
*
* 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.relational.core.mapping;
import java.lang.annotation.Documented;

View File

@@ -73,11 +73,15 @@ public interface RelationalPersistentProperty extends PersistentProperty<Relatio
/**
* @return true, if the Property is an embedded value object, otherwise false.
*/
boolean isEmbedded();
default boolean isEmbedded() {
return false;
};
/**
* @return Prefix for embedded columns. If the column is not embedded the return value is null.
*/
@Nullable
String getEmbeddedPrefix();
default String getEmbeddedPrefix() {
return null;
};
}

View File

@@ -24,6 +24,7 @@ import java.time.ZonedDateTime;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
import org.assertj.core.api.SoftAssertions;
import org.junit.Test;
@@ -103,23 +104,32 @@ public class BasicRelationalPersistentPropertyUnitTests {
@Test // DATAJDBC-111
public void detectsEmbeddedEntity() {
final RelationalPersistentEntity<?> requiredPersistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
final RelationalPersistentEntity<?> requiredPersistentEntity = context
.getRequiredPersistentEntity(DummyEntity.class);
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("someList").isEmbedded()).isFalse();
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("someList").getEmbeddedPrefix()).isNull();
SoftAssertions softly = new SoftAssertions();
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("id").isEmbedded()).isFalse();
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("id").getEmbeddedPrefix()).isNull();
BiConsumer<String, String> checkEmbedded = (name, prefix) -> {
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("embeddableEntity").isEmbedded()).isTrue();
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("embeddableEntity").getEmbeddedPrefix()).isEmpty();
RelationalPersistentProperty property = requiredPersistentEntity.getRequiredPersistentProperty(name);
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("prefixedEmbeddableEntity").isEmbedded()).isTrue();
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("prefixedEmbeddableEntity").getEmbeddedPrefix()).isEqualTo("prefix");
softly.assertThat(property.isEmbedded()) //
.describedAs(name + " is embedded") //
.isEqualTo(prefix != null);
softly.assertThat(property.getEmbeddedPrefix()) //
.describedAs(name + " prefix") //
.isEqualTo(prefix);
};
checkEmbedded.accept("someList", null);
checkEmbedded.accept("id", null);
checkEmbedded.accept("embeddableEntity", "");
checkEmbedded.accept("prefixedEmbeddableEntity", "prefix");
softly.assertAll();
}
private void checkTargetType(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity,
String propertyName, Class<?> expected) {
@@ -150,7 +160,6 @@ public class BasicRelationalPersistentPropertyUnitTests {
// DATAJDBC-111
private @Embedded("prefix") EmbeddableEntity prefixedEmbeddableEntity;
@Column("dummy_last_updated_at")
public LocalDateTime getLocalDateTime() {
return localDateTime;
@@ -172,7 +181,7 @@ public class BasicRelationalPersistentPropertyUnitTests {
// DATAJDBC-111
@Data
private static class EmbeddableEntity{
private static class EmbeddableEntity {
private final String embeddedTest;
}
}

View File

@@ -124,7 +124,8 @@ The properties of the following types are currently supported:
It is optional for one-to-one relationship entities to have an `id` attribute.
The table of the referenced entity is expected to have an additional column named the same as the table of the referencing entity.
You can change this name by implementing `NamingStrategy.getReverseColumnName(RelationalPersistentProperty property)`.
Embedded entities do not have an `id`.
Embedded entities do not need an `id`.
If one is present it gets ignored.
* `Set<some entity>` is considered a one-to-many relationship.
The table of the referenced entity is expected to have an additional column named the same as the table of the referencing entity.
@@ -273,7 +274,7 @@ public class MySubEntity {
====
[[jdbc.entity-persistence.embedded-entities]]
=== `Embedded entities`
=== Embedded entities
Embedded entities are used to have value objects in your java data model, even if there is only one table in your database.
In the following example you see, that `MyEntity` is mapped with the `@Embedded` annotation.
@@ -299,7 +300,6 @@ public class EmbeddedEntity {
If you need a value object multiple times in an entity, this can be achieved with the optional `value` element of the `@Embedded` annotation.
This element represents a prefix and is prepend for each column name in the embedded object.
[[jdbc.entity-persistence.state-detection-strategies]]
=== Entity State Detection Strategies