From 577d7643dd9eb894565a563737a4f485d0767a20 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Thu, 24 May 2018 12:18:27 +0200 Subject: [PATCH] DATAJDBC-221 - Added AggregateReference for references across aggregates. AggregateReferences can be used to reference other aggregates via their aggregate root without making them part of the referencing aggregate. I.e. the referenced entities will not be included in SQL statements for the referencing aggregates, apart from their id. Conversion between AggregateReferences and their ids and vice versa is done by the RelationalConverter. --- .../jdbc/core/DefaultDataAccessStrategy.java | 13 +- .../data/jdbc/core/EntityRowMapper.java | 4 +- .../jdbc/core/mapping/AggregateReference.java | 63 +++++++++ .../conversion/BasicRelationalConverter.java | 14 ++ .../BasicRelationalPersistentProperty.java | 30 +++++ .../mapping/RelationalMappingContext.java | 6 + .../mapping/RelationalPersistentProperty.java | 11 ++ .../data/jdbc/core/SqlGeneratorUnitTests.java | 24 +++- ...oryCrossAggregateHsqlIntegrationTests.java | 121 ++++++++++++++++++ ...lConverterAggregateReferenceUnitTests.java | 77 +++++++++++ ...RelationalPersistentPropertyUnitTests.java | 37 +++++- ...rossAggregateHsqlIntegrationTests-hsql.sql | 1 + 12 files changed, 383 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/springframework/data/jdbc/core/mapping/AggregateReference.java create mode 100644 src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests.java create mode 100644 src/test/java/org/springframework/data/relational/core/conversion/BasicRelationalConverterAggregateReferenceUnitTests.java create mode 100644 src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests-hsql.sql diff --git a/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java b/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java index 14e11f12..8f503467 100644 --- a/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java +++ b/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java @@ -285,13 +285,14 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { persistentEntity.doWithProperties((PropertyHandler) property -> { - if (!property.isEntity()) { - - Object value = propertyAccessor.getProperty(property); - - Object convertedValue = converter.writeValue(value, ClassTypeInformation.from(property.getColumnType())); - parameters.addValue(property.getColumnName(), convertedValue, JdbcUtil.sqlTypeFor(property.getColumnType())); + if (property.isEntity()) { + return; } + + Object value = propertyAccessor.getProperty(property); + Object convertedValue = converter.writeValue(value, ClassTypeInformation.from(property.getColumnType())); + parameters.addValue(property.getColumnName(), convertedValue, JdbcUtil.sqlTypeFor(property.getColumnType())); + }); return parameters; diff --git a/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java b/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java index 2fb226ec..f6fefd54 100644 --- a/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java +++ b/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java @@ -99,7 +99,9 @@ public class EntityRowMapper implements RowMapper { } else { - propertyAccessor.setProperty(property, readFrom(resultSet, property, "")); + final Object value = readFrom(resultSet, property, ""); + + propertyAccessor.setProperty(property, value); } } diff --git a/src/main/java/org/springframework/data/jdbc/core/mapping/AggregateReference.java b/src/main/java/org/springframework/data/jdbc/core/mapping/AggregateReference.java new file mode 100644 index 00000000..620d66c9 --- /dev/null +++ b/src/main/java/org/springframework/data/jdbc/core/mapping/AggregateReference.java @@ -0,0 +1,63 @@ +/* + * 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 org.springframework.data.jdbc.core.mapping; + +import lombok.RequiredArgsConstructor; + +import org.springframework.lang.Nullable; + +/** + * A reference to the aggregate root of a different aggregate. + * + * @param the type of the referenced aggregate root. + * @param the type of the id of the referenced aggregate root. + * + * @author Jens Schauder + * + * @since 1.0 + */ +public interface AggregateReference { + + static AggregateReference to(ID id) { + return new IdOnlyAggregateReference<>(id); + } + + /** + * @return the id of the referenced aggregate. May be {@code null}. + */ + @Nullable + ID getId(); + + /** + * An {@link AggregateReference} that only holds the id of the referenced aggregate root. + * + * Note that there is no check that a matching aggregate for this id actually exists. + * + * @param + * @param + */ + @RequiredArgsConstructor + class IdOnlyAggregateReference implements AggregateReference { + + private final ID id; + + @Override + public ID getId() { + return id; + } + } + +} diff --git a/src/main/java/org/springframework/data/relational/core/conversion/BasicRelationalConverter.java b/src/main/java/org/springframework/data/relational/core/conversion/BasicRelationalConverter.java index 0bb31773..ebdd0911 100644 --- a/src/main/java/org/springframework/data/relational/core/conversion/BasicRelationalConverter.java +++ b/src/main/java/org/springframework/data/relational/core/conversion/BasicRelationalConverter.java @@ -27,6 +27,7 @@ import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.convert.CustomConversions; import org.springframework.data.convert.CustomConversions.StoreConversions; import org.springframework.data.convert.EntityInstantiators; +import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; @@ -49,6 +50,7 @@ import org.springframework.util.ClassUtils; * Conversion is configurable by providing a customized {@link CustomConversions}. * * @author Mark Paluch + * @author Jens Schauder * @see MappingContext * @see SimpleTypeHolder * @see CustomConversions @@ -157,6 +159,14 @@ public class BasicRelationalConverter implements RelationalConverter { return conversionService.convert(value, type.getType()); } + if (AggregateReference.class.isAssignableFrom(type.getType())) { + + TypeInformation idType = type.getSuperTypeInformation(AggregateReference.class) + .getTypeArguments().get(1); + + return AggregateReference.to(readValue(value, idType)); + } + return getPotentiallyConvertedSimpleRead(value, type.getType()); } @@ -172,6 +182,10 @@ public class BasicRelationalConverter implements RelationalConverter { return null; } + if (AggregateReference.class.isAssignableFrom(value.getClass())) { + return writeValue (((AggregateReference) value).getId(), type); + } + Class rawType = type.getType(); RelationalPersistentEntity persistentEntity = context.getPersistentEntity(value.getClass()); diff --git a/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java b/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java index 2c553984..66ce056b 100644 --- a/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java +++ b/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java @@ -23,6 +23,8 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import org.springframework.data.jdbc.core.mapping.AggregateReference; +import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; @@ -96,6 +98,16 @@ class BasicRelationalPersistentProperty extends AnnotationBasedPersistentPropert throw new UnsupportedOperationException(); } + @Override + public boolean isEntity() { + return super.isEntity() && !isReference(); + } + + @Override + public boolean isReference() { + return AggregateReference.class.isAssignableFrom(getRawType()); + } + /* * (non-Javadoc) * @see org.springframework.data.jdbc.core.mapping.model.JdbcPersistentProperty#getColumnName() @@ -114,11 +126,20 @@ class BasicRelationalPersistentProperty extends AnnotationBasedPersistentPropert @Override public Class getColumnType() { + if (isReference()) { + return columnTypeForReference(); + } + Class columnType = columnTypeIfEntity(getActualType()); return columnType == null ? columnTypeForNonEntity(getActualType()) : columnType; } + @Override + public int getSqlType() { + return JdbcUtil.sqlTypeFor(getColumnType()); + } + @Override public RelationalPersistentEntity getOwner() { return (RelationalPersistentEntity) super.getOwner(); @@ -178,4 +199,13 @@ class BasicRelationalPersistentProperty extends AnnotationBasedPersistentPropert .findFirst() // .orElseGet(() -> ClassUtils.resolvePrimitiveIfNecessary(type)); } + + private Class columnTypeForReference() { + + Class componentType = getTypeInformation().getRequiredComponentType().getType(); + RelationalPersistentEntity referencedEntity = context.getRequiredPersistentEntity(componentType); + + return referencedEntity.getRequiredIdProperty().getColumnType(); + } + } diff --git a/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java b/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java index bcafc1ce..31ba7249 100644 --- a/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java +++ b/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java @@ -17,6 +17,7 @@ package org.springframework.data.relational.core.mapping; import lombok.Getter; +import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.context.MappingContext; @@ -78,4 +79,9 @@ public class RelationalMappingContext RelationalPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { return new BasicRelationalPersistentProperty(property, owner, simpleTypeHolder, this); } + + @Override + protected boolean shouldCreatePersistentEntityFor(TypeInformation type) { + return super.shouldCreatePersistentEntityFor(type) && !AggregateReference.class.isAssignableFrom(type.getType()); + } } diff --git a/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java b/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java index 1bf7c520..f1a31502 100644 --- a/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java +++ b/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java @@ -15,6 +15,7 @@ */ package org.springframework.data.relational.core.mapping; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.mapping.PersistentProperty; import org.springframework.lang.Nullable; @@ -26,6 +27,8 @@ import org.springframework.lang.Nullable; */ public interface RelationalPersistentProperty extends PersistentProperty { + boolean isReference(); + /** * Returns the name of the column backing this property. * @@ -40,6 +43,14 @@ public interface RelationalPersistentProperty extends PersistentProperty getColumnType(); + /** + * The SQL type constant used when using this property as a parameter for a SQL statement. + * @return Must not be {@code null}. + * + * @see java.sql.Types + */ + int getSqlType(); + @Override RelationalPersistentEntity getOwner(); diff --git a/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java index afe982fc..9578d6c7 100644 --- a/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java +++ b/src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java @@ -25,6 +25,7 @@ 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.AggregateReference; import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.relational.core.mapping.NamingStrategy; @@ -68,6 +69,7 @@ public class SqlGeneratorUnitTests { .startsWith("SELECT") // .contains("dummy_entity.x_id AS x_id,") // .contains("dummy_entity.x_name AS x_name,") // + .contains("dummy_entity.x_other AS x_other,") // .contains("ref.x_l1id AS ref_x_l1id") // .contains("ref.x_content AS ref_x_content").contains(" FROM dummy_entity") // // 1-N relationships do not get loaded via join @@ -139,9 +141,10 @@ public class SqlGeneratorUnitTests { // this would get called when DummyEntity is the element type of a Set String sql = sqlGenerator.getFindAllByProperty("back-ref", null, false); - assertThat(sql).isEqualTo("SELECT dummy_entity.x_id AS x_id, dummy_entity.x_name AS x_name, " - + "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, ref.x_further AS ref_x_further " - + "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.x_id " + assertThat(sql).isEqualTo("SELECT dummy_entity.x_id AS x_id, dummy_entity.x_name AS x_name, " // + + "dummy_entity.x_other AS x_other, " // + + "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, ref.x_further AS ref_x_further " // + + "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.x_id " // + "WHERE back-ref = :back-ref"); } @@ -152,6 +155,7 @@ public class SqlGeneratorUnitTests { String sql = sqlGenerator.getFindAllByProperty("back-ref", "key-column", false); assertThat(sql).isEqualTo("SELECT dummy_entity.x_id AS x_id, dummy_entity.x_name AS x_name, " // + + "dummy_entity.x_other AS x_other, " // + "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, ref.x_further AS ref_x_further, " // + "dummy_entity.key-column AS key-column " // + "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.x_id " // @@ -169,10 +173,11 @@ public class SqlGeneratorUnitTests { // this would get called when DummyEntity is th element type of a Map String sql = sqlGenerator.getFindAllByProperty("back-ref", "key-column", true); - assertThat(sql).isEqualTo("SELECT dummy_entity.x_id AS x_id, dummy_entity.x_name AS x_name, " - + "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, ref.x_further AS ref_x_further, " - + "dummy_entity.key-column AS key-column " - + "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.x_id " + assertThat(sql).isEqualTo("SELECT dummy_entity.x_id AS x_id, dummy_entity.x_name AS x_name, " // + + "dummy_entity.x_other AS x_other, " // + + "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, ref.x_further AS ref_x_further, " // + + "dummy_entity.key-column AS key-column " // + + "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.x_id " // + "WHERE back-ref = :back-ref " + "ORDER BY key-column"); } @@ -222,6 +227,7 @@ public class SqlGeneratorUnitTests { ReferencedEntity ref; Set elements; Map mappedElements; + AggregateReference other; } @SuppressWarnings("unused") @@ -250,7 +256,11 @@ public class SqlGeneratorUnitTests { } static class NoIdChild { + } + static class OtherAggregate { + @Id Long id; + String name; } private static class PrefixingNamingStrategy implements NamingStrategy { diff --git a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests.java new file mode 100644 index 00000000..c8f7ecc9 --- /dev/null +++ b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests.java @@ -0,0 +1,121 @@ +/* + * 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 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.core.mapping.AggregateReference; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; +import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; +import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.relational.core.mapping.RelationalMappingContext; +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. + * + * @author Jens Schauder + */ +@ContextConfiguration +@Transactional +public class JdbcRepositoryCrossAggregateHsqlIntegrationTests { + + private static final long TWO_ID = 23L; + + @Configuration + @Import(TestConfiguration.class) + @EnableJdbcRepositories(considerNestedRepositories = true) + static class Config { + + @Autowired JdbcRepositoryFactory factory; + + @Bean + Class testClass() { + return JdbcRepositoryCrossAggregateHsqlIntegrationTests.class; + } + } + + @ClassRule public static final SpringClassRule classRule = new SpringClassRule(); + @Rule public SpringMethodRule methodRule = new SpringMethodRule(); + + @Autowired NamedParameterJdbcTemplate template; + @Autowired Ones ones; + @Autowired RelationalMappingContext context; + + @SuppressWarnings("ConstantConditions") + @Test // DATAJDBC-221 + public void savesAndRead() { + + AggregateOne one = new AggregateOne(); + one.name = "Aggregate - 1"; + one.two = AggregateReference.to(TWO_ID); + + one = ones.save(one); + + AggregateOne reloaded = ones.findById(one.id).get(); + assertThat(reloaded.two.getId()).isEqualTo(TWO_ID); + } + + @Test // DATAJDBC-221 + public void savesAndUpdate() { + + AggregateOne one = new AggregateOne(); + one.name = "Aggregate - 1"; + one.two = AggregateReference.to(42L); + one = ones.save(one); + + one.two = AggregateReference.to(TWO_ID); + + ones.save(one); + + assertThat( // + JdbcTestUtils.countRowsInTableWhere( // + (JdbcTemplate) template.getJdbcOperations(), // + "aggregate_one", // + "two = " + TWO_ID) // + ).isEqualTo(1); + } + + interface Ones extends CrudRepository {} + + static class AggregateOne { + + @Id Long id; + String name; + AggregateReference two; + } + + static class AggregateTwo { + + @Id Long id; + String name; + } +} diff --git a/src/test/java/org/springframework/data/relational/core/conversion/BasicRelationalConverterAggregateReferenceUnitTests.java b/src/test/java/org/springframework/data/relational/core/conversion/BasicRelationalConverterAggregateReferenceUnitTests.java new file mode 100644 index 00000000..bd46c2df --- /dev/null +++ b/src/test/java/org/springframework/data/relational/core/conversion/BasicRelationalConverterAggregateReferenceUnitTests.java @@ -0,0 +1,77 @@ +/* + * 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 org.springframework.data.relational.core.conversion; + +import static org.assertj.core.api.Assertions.*; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Test; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.data.annotation.Id; +import org.springframework.data.jdbc.core.mapping.AggregateReference; +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 org.springframework.data.util.ClassTypeInformation; + +/** + * Unit tests for the handling of {@link AggregateReference}s in the + * {@link org.springframework.data.relational.core.conversion.BasicRelationalConverter}. + * + * @author Jens Schauder + */ +public class BasicRelationalConverterAggregateReferenceUnitTests { + + SoftAssertions softly = new SoftAssertions(); + + ConversionService conversionService = new DefaultConversionService(); + + RelationalMappingContext context = new RelationalMappingContext(); + RelationalConverter converter = new BasicRelationalConverter(context); + + RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); + + @Test // DATAJDBC-221 + public void convertsToAggregateReference() { + + final RelationalPersistentProperty property = entity.getRequiredPersistentProperty("reference"); + + Object readValue = converter.readValue(23, property.getTypeInformation()); + + assertThat(readValue).isInstanceOf(AggregateReference.class); + assertThat(((AggregateReference) readValue).getId()).isEqualTo(23L); + } + + @Test // DATAJDBC-221 + public void convertsFromAggregateReference() { + + final RelationalPersistentProperty property = entity.getRequiredPersistentProperty("reference"); + + AggregateReference reference = AggregateReference.to(23); + + Object writeValue = converter.writeValue(reference, ClassTypeInformation.from(property.getColumnType())); + + assertThat(writeValue).isEqualTo(23L); + } + + private static class DummyEntity { + + @Id + Long simple; + AggregateReference reference; + } +} diff --git a/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java b/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java index da8ebcea..8ae16569 100644 --- a/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java +++ b/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java @@ -27,6 +27,8 @@ import java.util.UUID; import org.assertj.core.api.SoftAssertions; import org.junit.Test; +import org.springframework.data.annotation.Id; +import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.mapping.PropertyHandler; /** @@ -39,13 +41,14 @@ import org.springframework.data.mapping.PropertyHandler; public class BasicRelationalPersistentPropertyUnitTests { RelationalMappingContext context = new RelationalMappingContext(); + RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); @Test // DATAJDBC-104 public void enumGetsStoredAsString() { RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class); - persistentEntity.doWithProperties((PropertyHandler) p -> { + entity.doWithProperties((PropertyHandler) p -> { switch (p.getName()) { case "someEnum": assertThat(p.getColumnType()).isEqualTo(String.class); @@ -90,13 +93,26 @@ public class BasicRelationalPersistentPropertyUnitTests { public void detectsAnnotatedColumnAndKeyName() { RelationalPersistentProperty listProperty = context // - .getRequiredPersistentEntity(DummyEntity.class) // - .getRequiredPersistentProperty("someList"); + .getRequiredPersistentEntity(DummyEntity.class) // + .getRequiredPersistentProperty("someList"); assertThat(listProperty.getReverseColumnName()).isEqualTo("dummy_column_name"); assertThat(listProperty.getKeyColumn()).isEqualTo("dummy_key_column_name"); } + @Test // DATAJDBC-221 + public void referencesAreNotEntitiesAndGetStoredAsTheirId() { + + SoftAssertions softly = new SoftAssertions(); + + RelationalPersistentProperty reference = entity.getRequiredPersistentProperty("reference"); + + softly.assertThat(reference.isEntity()).isFalse(); + softly.assertThat(reference.getColumnType()).isEqualTo(Long.class); + + softly.assertAll(); + } + private void checkTargetType(SoftAssertions softly, RelationalPersistentEntity persistentEntity, String propertyName, Class expected) { @@ -106,11 +122,15 @@ public class BasicRelationalPersistentPropertyUnitTests { } @Data + @SuppressWarnings("unused") private static class DummyEntity { + @Id private final Long id; private final SomeEnum someEnum; private final LocalDateTime localDateTime; private final ZonedDateTime zonedDateTime; + private final AggregateReference reference; + private final List listField; private final UUID uuid; @Column(value = "dummy_column_name", keyColumn = "dummy_key_column_name") private List someList; @@ -122,9 +142,18 @@ public class BasicRelationalPersistentPropertyUnitTests { public LocalDateTime getLocalDateTime() { return localDateTime; } + + public void setListSetter(Integer integer) { + + } + + public List getListGetter() { + return null; + } } + @SuppressWarnings("unused") private enum SomeEnum { - ALPHA; + ALPHA } } diff --git a/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests-hsql.sql b/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests-hsql.sql new file mode 100644 index 00000000..f03df7b7 --- /dev/null +++ b/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCrossAggregateHsqlIntegrationTests-hsql.sql @@ -0,0 +1 @@ +CREATE TABLE aggregate_one ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100), two INTEGER);