DATAJDBC-111 - Polishing.
Formatting. Removed some redundant tests. Some code simplifications. Original pull request: #110.
This commit is contained in:
@@ -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()));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
microsoft/mssql-server-linux:2017-CU6
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user