DATAJDBC-111 - Add support for embeddables.
By annotating a reference with `Embedded` that reference will get stored in the same table as the owning entity. Original pull request: #110.
This commit is contained in:
committed by
Jens Schauder
parent
9b856876fe
commit
7a26385b5a
@@ -50,6 +50,7 @@ import org.springframework.util.Assert;
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Thomas Lang
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
@@ -89,7 +90,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
|
||||
Map<String, Object> parameters = new LinkedHashMap<>(additionalParameters);
|
||||
|
||||
MapSqlParameterSource parameterSource = getPropertyMap(instance, persistentEntity);
|
||||
MapSqlParameterSource parameterSource = getPropertyMap(instance, persistentEntity, "");
|
||||
|
||||
Object idValue = getIdValueOrNull(instance, persistentEntity);
|
||||
RelationalPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
@@ -122,7 +123,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
RelationalPersistentEntity<S> persistentEntity = getRequiredPersistentEntity(domainType);
|
||||
|
||||
return operations.update(sql(domainType).getUpdate(), getPropertyMap(instance, persistentEntity)) != 0;
|
||||
return operations.update(sql(domainType).getUpdate(), getPropertyMap(instance, persistentEntity, "")) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -279,7 +280,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
return result;
|
||||
}
|
||||
|
||||
private <S> MapSqlParameterSource getPropertyMap(final S instance, RelationalPersistentEntity<S> persistentEntity) {
|
||||
private <S, T> MapSqlParameterSource getPropertyMap(final S instance, RelationalPersistentEntity<S> persistentEntity, String prefix) {
|
||||
|
||||
MapSqlParameterSource parameters = new MapSqlParameterSource();
|
||||
|
||||
@@ -287,14 +288,20 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
persistentEntity.doWithProperties((PropertyHandler<RelationalPersistentProperty>) property -> {
|
||||
|
||||
if (property.isEntity()) {
|
||||
if (property.isEntity() && !property.isEmbedded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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.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());
|
||||
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()));
|
||||
}
|
||||
});
|
||||
|
||||
return parameters;
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @author Maciej Walkowiak
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
@@ -105,12 +106,15 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object readOrLoadProperty(ResultSet resultSet, @Nullable Object id, RelationalPersistentProperty property, String prefix) {
|
||||
private Object readOrLoadProperty(ResultSet resultSet, @Nullable Object id, RelationalPersistentProperty property,
|
||||
String prefix) {
|
||||
|
||||
if (property.isCollectionLike() && id != null) {
|
||||
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()) {
|
||||
return readEmbeddedEntityFrom(resultSet, id, property, prefix);
|
||||
} else {
|
||||
return readFrom(resultSet, property, prefix);
|
||||
}
|
||||
@@ -126,9 +130,8 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
*/
|
||||
@Nullable
|
||||
private Object readFrom(ResultSet resultSet, RelationalPersistentProperty property, String prefix) {
|
||||
|
||||
if (property.isEntity()) {
|
||||
return readEntityFrom(resultSet, property);
|
||||
return readEntityFrom(resultSet, property, prefix);
|
||||
}
|
||||
|
||||
Object value = getObjectFromResultSet(resultSet, prefix + property.getColumnName());
|
||||
@@ -137,9 +140,28 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <S> S readEntityFrom(ResultSet rs, RelationalPersistentProperty property) {
|
||||
private <S> S readEmbeddedEntityFrom(ResultSet rs, @Nullable Object id, RelationalPersistentProperty property, String prefix) {
|
||||
String newPrefix = prefix + property.getEmbeddedPrefix();
|
||||
|
||||
String prefix = property.getName() + "_";
|
||||
@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);
|
||||
|
||||
for (RelationalPersistentProperty p : entity) {
|
||||
accessor.setProperty(p, readOrLoadProperty(rs, id, p, newPrefix));
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <S> S readEntityFrom(ResultSet rs, RelationalPersistentProperty property, String prefix) {
|
||||
|
||||
String newPrefix = prefix + property.getName() + "_";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
RelationalPersistentEntity<S> entity = (RelationalPersistentEntity<S>) context
|
||||
@@ -150,22 +172,22 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
Object idValue = null;
|
||||
|
||||
if (idProperty != null) {
|
||||
idValue = readFrom(rs, idProperty, prefix);
|
||||
idValue = readFrom(rs, idProperty, newPrefix);
|
||||
}
|
||||
|
||||
if ((idProperty != null //
|
||||
? idValue //
|
||||
: getObjectFromResultSet(rs, prefix + property.getReverseColumnName()) //
|
||||
: getObjectFromResultSet(rs, newPrefix + property.getReverseColumnName()) //
|
||||
) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
S instance = createInstance(entity, rs, idValue, prefix);
|
||||
S instance = createInstance(entity, rs, idValue, newPrefix);
|
||||
|
||||
PersistentPropertyAccessor<S> accessor = converter.getPropertyAccessor(entity, instance);
|
||||
|
||||
for (RelationalPersistentProperty p : entity) {
|
||||
accessor.setProperty(p, readFrom(rs, p, prefix));
|
||||
accessor.setProperty(p, readOrLoadProperty(rs, idValue, p, newPrefix));
|
||||
}
|
||||
|
||||
return instance;
|
||||
@@ -181,7 +203,8 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private <S> S createInstance(RelationalPersistentEntity<S> entity, ResultSet rs, @Nullable Object idValue, String prefix) {
|
||||
private <S> S createInstance(RelationalPersistentEntity<S> entity, ResultSet rs, @Nullable Object idValue,
|
||||
String prefix) {
|
||||
|
||||
return converter.createInstance(entity, parameter -> {
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Yoichi Imai
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
class SqlGenerator {
|
||||
|
||||
@@ -67,22 +68,35 @@ class SqlGenerator {
|
||||
this.context = context;
|
||||
this.entity = entity;
|
||||
this.sqlGeneratorSource = sqlGeneratorSource;
|
||||
initColumnNames();
|
||||
initColumnNames(entity, "");
|
||||
}
|
||||
|
||||
private void initColumnNames() {
|
||||
|
||||
entity.doWithProperties((PropertyHandler<RelationalPersistentProperty>) p -> {
|
||||
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 (!p.isEntity()) {
|
||||
columnNames.add(p.getColumnName());
|
||||
if (!entity.isIdProperty(p)) {
|
||||
nonIdColumnNames.add(p.getColumnName());
|
||||
}
|
||||
if (!property.isEntity()) {
|
||||
initSimpleColumnName(property, prefix);
|
||||
} else if (property.isEmbedded()) {
|
||||
initEmbeddedColumnNames(property, prefix);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
initColumnNames(embeddedEntity, prefix + embeddedPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a query for selecting all simple properties of an entitty, including those for one-to-one relationhships.
|
||||
* Results are filtered using an {@code IN}-clause on the id column.
|
||||
@@ -167,8 +181,9 @@ class SqlGenerator {
|
||||
private SelectBuilder createSelectBuilder() {
|
||||
|
||||
SelectBuilder builder = new SelectBuilder(entity.getTableName());
|
||||
addColumnsForSimpleProperties(builder);
|
||||
addColumnsAndJoinsForOneToOneReferences(builder);
|
||||
addColumnsForSimpleProperties(entity, "", "", entity, builder);
|
||||
addColumnsForEmbeddedProperties(entity, "", "", entity, builder);
|
||||
addColumnsAndJoinsForOneToOneReferences(entity, "", "", entity, builder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
@@ -177,31 +192,46 @@ class SqlGenerator {
|
||||
* Adds the columns to the provided {@link SelectBuilder} representing simplem properties, including those from
|
||||
* one-to-one relationships.
|
||||
*
|
||||
* @param rootEntity
|
||||
* @param builder The {@link SelectBuilder} to be modified.
|
||||
*/
|
||||
private void addColumnsAndJoinsForOneToOneReferences(SelectBuilder builder) {
|
||||
private void addColumnsAndJoinsForOneToOneReferences(RelationalPersistentEntity<?> entity, String prefix,
|
||||
String tableAlias, RelationalPersistentEntity<?> rootEntity, SelectBuilder builder) {
|
||||
|
||||
for (RelationalPersistentProperty property : entity) {
|
||||
if (!property.isEntity() //
|
||||
|| property.isEmbedded() //
|
||||
|| Collection.class.isAssignableFrom(property.getType()) //
|
||||
|| Map.class.isAssignableFrom(property.getType()) //
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RelationalPersistentEntity<?> refEntity = context.getRequiredPersistentEntity(property.getActualType());
|
||||
String joinAlias = property.getName();
|
||||
builder.join(jb -> jb.leftOuter().table(refEntity.getTableName()).as(joinAlias) //
|
||||
.where(property.getReverseColumnName()).eq().column(entity.getTableName(), entity.getIdColumn()));
|
||||
final RelationalPersistentEntity<?> refEntity = context.getRequiredPersistentEntity(property.getActualType());
|
||||
final String joinAlias;
|
||||
|
||||
for (RelationalPersistentProperty refProperty : refEntity) {
|
||||
builder.column( //
|
||||
cb -> cb.tableAlias(joinAlias) //
|
||||
.column(refProperty.getColumnName()) //
|
||||
.as(joinAlias + "_" + refProperty.getColumnName()) //
|
||||
);
|
||||
if (tableAlias.isEmpty()) {
|
||||
if (prefix.isEmpty()) {
|
||||
joinAlias = property.getName();
|
||||
} else {
|
||||
joinAlias = prefix + property.getName();
|
||||
}
|
||||
} else {
|
||||
if (prefix.isEmpty()) {
|
||||
joinAlias = tableAlias + "_" + property.getName();
|
||||
} else {
|
||||
joinAlias = tableAlias + "_" + prefix + property.getName();
|
||||
}
|
||||
}
|
||||
|
||||
// final String joinAlias = tableAlias.isEmpty() ? property.getName() : tableAlias + "_" + property.getName();
|
||||
builder.join(jb -> jb.leftOuter().table(refEntity.getTableName()).as(joinAlias) //
|
||||
.where(property.getReverseColumnName()).eq().column(rootEntity.getTableName(), rootEntity.getIdColumn()));
|
||||
|
||||
addColumnsForSimpleProperties(refEntity, "", joinAlias, refEntity, builder);
|
||||
addColumnsForEmbeddedProperties(refEntity, "", joinAlias, refEntity, builder);
|
||||
addColumnsAndJoinsForOneToOneReferences(refEntity, "", joinAlias, refEntity, builder);
|
||||
|
||||
// if the referenced property doesn't have an id, include the back reference in the select list.
|
||||
// this enables determining if the referenced entity is present or null.
|
||||
if (!refEntity.hasIdProperty()) {
|
||||
@@ -215,18 +245,39 @@ class SqlGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private void addColumnsForSimpleProperties(SelectBuilder builder) {
|
||||
private void addColumnsForEmbeddedProperties(RelationalPersistentEntity<?> currentEntity, String prefix,
|
||||
String tableAlias, RelationalPersistentEntity<?> rootEntity, SelectBuilder builder) {
|
||||
for (RelationalPersistentProperty property : currentEntity) {
|
||||
if (!property.isEmbedded()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (RelationalPersistentProperty property : entity) {
|
||||
final String embeddedPrefix = prefix + property.getEmbeddedPrefix();
|
||||
final RelationalPersistentEntity<?> embeddedEntity = context
|
||||
.getRequiredPersistentEntity(property.getColumnType());
|
||||
|
||||
addColumnsForSimpleProperties(embeddedEntity, embeddedPrefix, tableAlias, rootEntity, builder);
|
||||
addColumnsForEmbeddedProperties(embeddedEntity, embeddedPrefix, tableAlias, rootEntity, builder);
|
||||
addColumnsAndJoinsForOneToOneReferences(embeddedEntity, embeddedPrefix, tableAlias, rootEntity, builder);
|
||||
}
|
||||
}
|
||||
|
||||
private void addColumnsForSimpleProperties(RelationalPersistentEntity<?> currentEntity, String prefix,
|
||||
String tableAlias, RelationalPersistentEntity<?> rootEntity, SelectBuilder builder) {
|
||||
|
||||
for (RelationalPersistentProperty property : currentEntity) {
|
||||
|
||||
if (property.isEntity()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String column = prefix + property.getColumnName();
|
||||
final String as = tableAlias.isEmpty() ? column : tableAlias + "_" + column;
|
||||
|
||||
builder.column(cb -> cb //
|
||||
.tableAlias(entity.getTableName()) //
|
||||
.column(property.getColumnName()) //
|
||||
.as(property.getColumnName()));
|
||||
.tableAlias(tableAlias.isEmpty() ? rootEntity.getTableName() : tableAlias) //
|
||||
.column(column) //
|
||||
.as(as));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,9 +358,8 @@ class SqlGenerator {
|
||||
|
||||
RelationalPersistentProperty property = path.getBaseProperty();
|
||||
|
||||
String innerMostCondition = String.format("%s IS NOT NULL", property.getReverseColumnName());
|
||||
|
||||
String condition = cascadeConditions(innerMostCondition, getSubPath(path));
|
||||
final String innerMostCondition1 = createInnerMostCondition("%s IS NOT NULL", path);
|
||||
String condition = cascadeConditions(innerMostCondition1, getSubPath(path));
|
||||
|
||||
return String.format("DELETE FROM %s WHERE %s", entityToDelete.getTableName(), condition);
|
||||
}
|
||||
@@ -322,15 +372,23 @@ class SqlGenerator {
|
||||
|
||||
RelationalPersistentEntity<?> entityToDelete = context
|
||||
.getRequiredPersistentEntity(path.getRequiredLeafProperty().getActualType());
|
||||
RelationalPersistentProperty property = path.getBaseProperty();
|
||||
|
||||
String innerMostCondition = String.format("%s = :rootId", property.getReverseColumnName());
|
||||
|
||||
final String innerMostCondition = createInnerMostCondition("%s = :rootId", path);
|
||||
String condition = cascadeConditions(innerMostCondition, getSubPath(path));
|
||||
|
||||
return String.format("DELETE FROM %s WHERE %s", entityToDelete.getTableName(), condition);
|
||||
}
|
||||
|
||||
private String createInnerMostCondition(String template, PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
PersistentPropertyPath<RelationalPersistentProperty> currentPath = path;
|
||||
while (!currentPath.getParentPath().isEmpty() && !currentPath.getParentPath().getRequiredLeafProperty().isEmbedded()){
|
||||
currentPath = currentPath.getParentPath();
|
||||
}
|
||||
|
||||
RelationalPersistentProperty property = currentPath.getRequiredLeafProperty();
|
||||
return String.format(template, property.getReverseColumnName());
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getSubPath(
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
|
||||
@@ -338,11 +396,21 @@ class SqlGenerator {
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> ancestor = path;
|
||||
|
||||
for (int i = pathLength - 1; i > 0; i--) {
|
||||
ancestor = path.getParentPath();
|
||||
int embeddedDepth = 0;
|
||||
while (!ancestor.getParentPath().isEmpty() && ancestor.getParentPath().getRequiredLeafProperty().isEmbedded()) {
|
||||
embeddedDepth++;
|
||||
ancestor = ancestor.getParentPath();
|
||||
}
|
||||
|
||||
return path.getExtensionForBaseOf(ancestor);
|
||||
ancestor = path;
|
||||
|
||||
for (int i = pathLength - 1 + embeddedDepth; i > 0; i--) {
|
||||
ancestor = ancestor.getParentPath();
|
||||
}
|
||||
|
||||
final PersistentPropertyPath<RelationalPersistentProperty> extensionForBaseOf = path
|
||||
.getExtensionForBaseOf(ancestor);
|
||||
return extensionForBaseOf;
|
||||
}
|
||||
|
||||
private String cascadeConditions(String innerCondition, PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
@@ -351,8 +419,13 @@ class SqlGenerator {
|
||||
return innerCondition;
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> rootPath = path;
|
||||
while (rootPath.getLength() > 1) {
|
||||
rootPath = rootPath.getParentPath();
|
||||
}
|
||||
|
||||
RelationalPersistentEntity<?> entity = context
|
||||
.getRequiredPersistentEntity(path.getBaseProperty().getOwner().getTypeInformation());
|
||||
.getRequiredPersistentEntity(rootPath.getBaseProperty().getOwner().getTypeInformation());
|
||||
RelationalPersistentProperty property = path.getRequiredLeafProperty();
|
||||
|
||||
return String.format("%s IN (SELECT %s FROM %s WHERE %s)", //
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
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;
|
||||
@@ -59,6 +60,7 @@ import org.springframework.util.Assert;
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Maciej Walkowiak
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public class EntityRowMapperUnitTests {
|
||||
|
||||
@@ -147,6 +149,21 @@ public class EntityRowMapperUnitTests {
|
||||
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void simpleEmbeddedGetsProperlyExtracted() throws SQLException {
|
||||
|
||||
ResultSet rs = mockResultSet(asList("id", "name", "prefix_id", "prefix_name"), //
|
||||
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta");
|
||||
rs.next();
|
||||
|
||||
EmbeddedEntity extracted = createRowMapper(EmbeddedEntity.class).mapRow(rs, 1);
|
||||
|
||||
assertThat(extracted) //
|
||||
.isNotNull() //
|
||||
.extracting(e -> e.id, e -> e.name, e -> e.children.id, e -> e.children.name) //
|
||||
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
public void collectionReferenceGetsLoadedWithAdditionalSelect() throws SQLException {
|
||||
|
||||
@@ -417,6 +434,13 @@ public class EntityRowMapperUnitTests {
|
||||
List<Trivial> children;
|
||||
}
|
||||
|
||||
static class EmbeddedEntity {
|
||||
|
||||
@Id Long id;
|
||||
String name;
|
||||
@Embedded("prefix_") Trivial children;
|
||||
}
|
||||
|
||||
private static class DontUseSetter {
|
||||
String value;
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 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.
|
||||
*
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public class SqlGeneratorEmbeddedUnitTests {
|
||||
|
||||
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.attr1 AS attr1")
|
||||
.contains("dummy_entity.attr2 AS attr2")
|
||||
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
|
||||
.contains("dummy_entity.prefix_attr2 AS prefix_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.attr1 AS attr1")
|
||||
.contains("dummy_entity.attr2 AS attr2")
|
||||
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
|
||||
.contains("dummy_entity.prefix_attr2 AS prefix_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.attr1 AS attr1")
|
||||
.contains("dummy_entity.attr2 AS attr2")
|
||||
.contains("dummy_entity.prefix_attr1 AS prefix_attr1")
|
||||
.contains("dummy_entity.prefix_attr2 AS prefix_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(":attr1")
|
||||
.contains(":attr2")
|
||||
.contains(":prefix_attr1")
|
||||
.contains(":prefix_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("attr1 = :attr1")
|
||||
.contains("attr2 = :attr2")
|
||||
.contains("prefix_attr1 = :prefix_attr1")
|
||||
.contains("prefix_attr2 = :prefix_attr2");
|
||||
softAssertions.assertAll();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class DummyEntity {
|
||||
|
||||
@Column("id1")
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Embedded("prefix_")
|
||||
Embeddable prefixedEmbeddable;
|
||||
|
||||
@Embedded
|
||||
Embeddable embeddable;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Embeddable
|
||||
{
|
||||
Long attr1;
|
||||
String attr2;
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ public class SqlGeneratorUnitTests {
|
||||
assertThat(sql).isEqualTo("DELETE FROM element WHERE dummy_entity = :rootId");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131
|
||||
@Test // DATAJDBC-131, DATAJDBC-111
|
||||
public void findAllByProperty() {
|
||||
|
||||
// this would get called when ListParent is the element type of a Set
|
||||
@@ -147,12 +147,15 @@ public class SqlGeneratorUnitTests {
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, 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.id1 " //
|
||||
+ "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, "
|
||||
+ "ref_further.x_l2id AS ref_further_x_l2id, ref_further.x_something AS ref_further_x_something " //
|
||||
+ "FROM dummy_entity "
|
||||
+ "LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1 " //
|
||||
+ "LEFT OUTER JOIN second_level_referenced_entity AS ref_further ON ref_further.referenced_entity = referenced_entity.x_l1id " //
|
||||
+ "WHERE back-ref = :back-ref");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131
|
||||
@Test // DATAJDBC-131, DATAJDBC-111
|
||||
public void findAllByPropertyWithKey() {
|
||||
|
||||
// this would get called when ListParent is th element type of a Map
|
||||
@@ -160,9 +163,12 @@ public class SqlGeneratorUnitTests {
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, 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, " //
|
||||
+ "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, "
|
||||
+ "ref_further.x_l2id AS ref_further_x_l2id, ref_further.x_something AS ref_further_x_something, " //
|
||||
+ "dummy_entity.key-column AS key-column " //
|
||||
+ "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1 " //
|
||||
+ "FROM dummy_entity "
|
||||
+ "LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1 " //
|
||||
+ "LEFT OUTER JOIN second_level_referenced_entity AS ref_further ON ref_further.referenced_entity = referenced_entity.x_l1id " //
|
||||
+ "WHERE back-ref = :back-ref");
|
||||
}
|
||||
|
||||
@@ -171,7 +177,7 @@ public class SqlGeneratorUnitTests {
|
||||
String sql = sqlGenerator.getFindAllByProperty("back-ref", null, true);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131
|
||||
@Test // DATAJDBC-131, DATAJDBC-111
|
||||
public void findAllByPropertyWithKeyOrdered() {
|
||||
|
||||
// this would get called when ListParent is th element type of a Map
|
||||
@@ -179,9 +185,12 @@ public class SqlGeneratorUnitTests {
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, 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, " //
|
||||
+ "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, "
|
||||
+ "ref_further.x_l2id AS ref_further_x_l2id, ref_further.x_something AS ref_further_x_something, " //
|
||||
+ "dummy_entity.key-column AS key-column " //
|
||||
+ "FROM dummy_entity LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1 " //
|
||||
+ "FROM dummy_entity "
|
||||
+ "LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1 " //
|
||||
+ "LEFT OUTER JOIN second_level_referenced_entity AS ref_further ON ref_further.referenced_entity = referenced_entity.x_l1id " //
|
||||
+ "WHERE back-ref = :back-ref " + "ORDER BY key-column");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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 lombok.Value;
|
||||
import lombok.experimental.Wither;
|
||||
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 {@link Embedded} annotation in Entities.
|
||||
*
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class JdbcRepositoryEmbeddedImmutableIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryEmbeddedImmutableIntegrationTests.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().getAttr1()).isEqualTo(entity.getPrefixedEmbeddable().getAttr1());
|
||||
assertThat(it.getPrefixedEmbeddable().getAttr2()).isEqualTo(entity.getPrefixedEmbeddable().getAttr2());
|
||||
});
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
|
||||
|
||||
@Data
|
||||
static class DummyEntity {
|
||||
|
||||
@Id Long id;
|
||||
|
||||
@Embedded("prefix_") Embeddable prefixedEmbeddable;
|
||||
}
|
||||
|
||||
@Value
|
||||
@Wither
|
||||
private static class Embeddable {
|
||||
Long attr1;
|
||||
String attr2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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 {@link Embedded} annotation in Entities.
|
||||
*
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class JdbcRepositoryEmbeddedIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryEmbeddedIntegrationTests.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().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());
|
||||
});
|
||||
}
|
||||
|
||||
@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().setAttr2("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.getEmbeddable().setAttr2("something else");
|
||||
other.getEmbeddable().setAttr2("others Name");
|
||||
|
||||
repository.saveAll(asList(entity, other));
|
||||
|
||||
assertThat(repository.findAll()) //
|
||||
.extracting(d -> d.getEmbeddable().getAttr2()) //
|
||||
.containsExactlyInAnyOrder(entity.getEmbeddable().getAttr2(), other.getEmbeddable().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();
|
||||
|
||||
final Embeddable prefixedEmbeddable = new Embeddable();
|
||||
prefixedEmbeddable.setAttr1(1L);
|
||||
prefixedEmbeddable.setAttr2("test1");
|
||||
entity.setPrefixedEmbeddable(prefixedEmbeddable);
|
||||
|
||||
final Embeddable embeddable = new Embeddable();
|
||||
embeddable.setAttr1(2L);
|
||||
embeddable.setAttr2("test2");
|
||||
entity.setEmbeddable(embeddable);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
|
||||
|
||||
@Data
|
||||
static class DummyEntity {
|
||||
|
||||
@Id Long id;
|
||||
|
||||
@Embedded("prefix_") Embeddable prefixedEmbeddable;
|
||||
|
||||
@Embedded Embeddable embeddable;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Embeddable {
|
||||
Long attr1;
|
||||
String attr2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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.Column;
|
||||
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 JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryEmbeddedNotInAggregateRootIntegrationTests.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);
|
||||
|
||||
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity2",
|
||||
"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.getDummyEntity2().getTest()).isEqualTo(entity.getDummyEntity2().getTest());
|
||||
assertThat(it.getDummyEntity2().getEmbeddable().getAttr()).isEqualTo(entity.getDummyEntity2().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.getDummyEntity2().setTest("something else");
|
||||
entity.getDummyEntity2().getEmbeddable().setAttr(3L);
|
||||
DummyEntity saved = repository.save(entity);
|
||||
|
||||
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
|
||||
assertThat(it.getDummyEntity2().getTest()).isEqualTo(saved.getDummyEntity2().getTest());
|
||||
assertThat(it.getDummyEntity2().getEmbeddable().getAttr()).isEqualTo(saved.getDummyEntity2().getEmbeddable().getAttr());
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void updateMany() {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
DummyEntity other = repository.save(createDummyEntity());
|
||||
|
||||
entity.getDummyEntity2().setTest("something else");
|
||||
other.getDummyEntity2().setTest("others Name");
|
||||
|
||||
entity.getDummyEntity2().getEmbeddable().setAttr(3L);
|
||||
other.getDummyEntity2().getEmbeddable().setAttr(5L);
|
||||
|
||||
repository.saveAll(asList(entity, other));
|
||||
|
||||
assertThat(repository.findAll()) //
|
||||
.extracting(d -> d.getDummyEntity2().getTest()) //
|
||||
.containsExactlyInAnyOrder(entity.getDummyEntity2().getTest(), other.getDummyEntity2().getTest());
|
||||
|
||||
assertThat(repository.findAll()) //
|
||||
.extracting(d -> d.getDummyEntity2().getEmbeddable().getAttr()) //
|
||||
.containsExactlyInAnyOrder(entity.getDummyEntity2().getEmbeddable().getAttr(), other.getDummyEntity2().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();
|
||||
|
||||
entity.setTest("rootTest");
|
||||
|
||||
final DummyEntity2 dummyEntity2 = new DummyEntity2();
|
||||
dummyEntity2.setTest("c1");
|
||||
|
||||
final Embeddable embeddable = new Embeddable();
|
||||
embeddable.setAttr(1L);
|
||||
dummyEntity2.setEmbeddable(embeddable);
|
||||
|
||||
entity.setDummyEntity2(dummyEntity2);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
|
||||
|
||||
@Data
|
||||
static class DummyEntity {
|
||||
@Id Long id;
|
||||
|
||||
String test;
|
||||
|
||||
@Column("id")
|
||||
DummyEntity2 dummyEntity2;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class DummyEntity2 {
|
||||
@Id Long id;
|
||||
|
||||
String test;
|
||||
|
||||
@Embedded("prefix_")
|
||||
Embeddable embeddable;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Embeddable {
|
||||
Long attr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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.Column;
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Very simple use cases for creation and usage of JdbcRepositories with test {@link Embedded} annotation in Entities.
|
||||
*
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryEmbeddedWithCollectionIntegrationTests.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);
|
||||
|
||||
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity2",
|
||||
"id = " + entity.getId())).isEqualTo(2);
|
||||
}
|
||||
|
||||
@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.getEmbeddable().getTest()).isEqualTo(entity.getEmbeddable().getTest());
|
||||
assertThat(it.getEmbeddable().getList().size()).isEqualTo(entity.getEmbeddable().getList().size());
|
||||
assertThat(it.getEmbeddable().getList().get(0).getTest()).isEqualTo(entity.getEmbeddable().getList().get(0).getTest());
|
||||
assertThat(it.getEmbeddable().getList().get(1).getTest()).isEqualTo(entity.getEmbeddable().getList().get(1).getTest());
|
||||
});
|
||||
}
|
||||
|
||||
@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.getEmbeddable().setTest("something else");
|
||||
entity.getEmbeddable().getList().get(0).setTest("another");
|
||||
DummyEntity saved = repository.save(entity);
|
||||
|
||||
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
|
||||
assertThat(it.getId()).isEqualTo(saved.getId());
|
||||
assertThat(it.getEmbeddable().getTest()).isEqualTo(saved.getEmbeddable().getTest());
|
||||
assertThat(it.getEmbeddable().getList().size()).isEqualTo(saved.getEmbeddable().getList().size());
|
||||
assertThat(it.getEmbeddable().getList().get(0).getTest()).isEqualTo(saved.getEmbeddable().getList().get(0).getTest());
|
||||
assertThat(it.getEmbeddable().getList().get(1).getTest()).isEqualTo(saved.getEmbeddable().getList().get(1).getTest());
|
||||
});
|
||||
}
|
||||
|
||||
@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.getEmbeddable().getList().get(0).setTest("else");
|
||||
other.getEmbeddable().getList().get(0).setTest("Name");
|
||||
|
||||
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.getEmbeddable().getList().get(0).getTest()) //
|
||||
.containsExactlyInAnyOrder(entity.getEmbeddable().getList().get(0).getTest(), other.getEmbeddable().getList().get(0).getTest());
|
||||
}
|
||||
|
||||
@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.setTest("root");
|
||||
|
||||
final Embeddable embeddable = new Embeddable();
|
||||
embeddable.setTest("embedded");
|
||||
|
||||
final DummyEntity2 dummyEntity21 = new DummyEntity2();
|
||||
dummyEntity21.setTest("entity1");
|
||||
|
||||
final DummyEntity2 dummyEntity22 = new DummyEntity2();
|
||||
dummyEntity22.setTest("entity2");
|
||||
|
||||
embeddable.getList().add(dummyEntity21);
|
||||
embeddable.getList().add(dummyEntity22);
|
||||
|
||||
entity.setEmbeddable(embeddable);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
|
||||
|
||||
@Data
|
||||
private static class DummyEntity {
|
||||
@Id Long id;
|
||||
|
||||
String test;
|
||||
|
||||
@Embedded("prefix_")
|
||||
Embeddable embeddable;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Embeddable {
|
||||
@Column(value = "id", keyColumn = "order_key")
|
||||
List<DummyEntity2> list = new ArrayList<>();
|
||||
|
||||
String test;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class DummyEntity2 {
|
||||
String test;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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.Column;
|
||||
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 JdbcRepositoryEmbeddedWithReferenceIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryEmbeddedWithReferenceIntegrationTests.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);
|
||||
|
||||
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity2",
|
||||
"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.getEmbeddable().getTest()).isEqualTo(entity.getEmbeddable().getTest());
|
||||
assertThat(it.getEmbeddable().getDummyEntity2().getTest()).isEqualTo(entity.getEmbeddable().getDummyEntity2().getTest());
|
||||
});
|
||||
}
|
||||
|
||||
@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.getEmbeddable().setTest("something else");
|
||||
entity.getEmbeddable().getDummyEntity2().setTest("another");
|
||||
DummyEntity saved = repository.save(entity);
|
||||
|
||||
assertThat(repository.findById(entity.getId())).hasValueSatisfying(it -> {
|
||||
assertThat(it.getEmbeddable().getTest()).isEqualTo(saved.getEmbeddable().getTest());
|
||||
assertThat(it.getEmbeddable().getDummyEntity2().getTest()).isEqualTo(saved.getEmbeddable().getDummyEntity2().getTest());
|
||||
});
|
||||
}
|
||||
|
||||
@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.getEmbeddable().getDummyEntity2().setTest("else");
|
||||
other.getEmbeddable().getDummyEntity2().setTest("Name");
|
||||
|
||||
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.getEmbeddable().getDummyEntity2().getTest()) //
|
||||
.containsExactlyInAnyOrder(entity.getEmbeddable().getDummyEntity2().getTest(), other.getEmbeddable().getDummyEntity2().getTest());
|
||||
}
|
||||
|
||||
@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.setTest("root");
|
||||
|
||||
final Embeddable embeddable = new Embeddable();
|
||||
embeddable.setTest("embedded");
|
||||
|
||||
final DummyEntity2 dummyEntity2 = new DummyEntity2();
|
||||
dummyEntity2.setTest("entity");
|
||||
|
||||
embeddable.setDummyEntity2(dummyEntity2);
|
||||
|
||||
entity.setEmbeddable(embeddable);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
|
||||
|
||||
@Data
|
||||
private static class DummyEntity {
|
||||
@Id Long id;
|
||||
|
||||
String test;
|
||||
|
||||
@Embedded("prefix_")
|
||||
Embeddable embeddable;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Embeddable {
|
||||
@Column("id")
|
||||
DummyEntity2 dummyEntity2;
|
||||
|
||||
String test;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class DummyEntity2 {
|
||||
|
||||
@Id Long id;
|
||||
|
||||
String test;
|
||||
}
|
||||
}
|
||||
@@ -115,8 +115,6 @@ public class JdbcRepositoryConfigExtensionUnitTests {
|
||||
assertThat(jdbcOperations) //
|
||||
.isInstanceOf(RuntimeBeanReference.class) //
|
||||
.extracting(rbr -> ((RuntimeBeanReference) rbr).getBeanName()).contains("two");
|
||||
|
||||
System.out.println(jdbcOperations);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-293
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
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)
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);
|
||||
@@ -0,0 +1,2 @@
|
||||
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);
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);
|
||||
@@ -0,0 +1,2 @@
|
||||
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);
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100))
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
|
||||
@@ -0,0 +1,2 @@
|
||||
DROP TABLE IF EXISTS dummy_entity;
|
||||
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
|
||||
@@ -0,0 +1,2 @@
|
||||
DROP TABLE dummy_entity;
|
||||
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
|
||||
@@ -0,0 +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))
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
|
||||
@@ -0,0 +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));
|
||||
@@ -0,0 +1 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, ATTR1 BIGINT, ATTR2 VARCHAR(100), PREFIX_ATTR1 BIGINT, PREFIX_ATTR2 VARCHAR(100));
|
||||
@@ -0,0 +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));
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100))
|
||||
CREATE TABLE dummy_entity2 ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT)
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT);
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE IF EXISTS dummy_entity;
|
||||
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, TEST VARCHAR(100));
|
||||
DROP TABLE IF EXISTS dummy_entity2;
|
||||
CREATE TABLE dummy_entity2 (id BIGINT PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT);
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT);
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE dummy_entity;
|
||||
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100));
|
||||
DROP TABLE dummy_entity2;
|
||||
CREATE TABLE dummy_entity2 (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX_ATTR BIGINT);
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 ( id BIGINT, ORDER_KEY BIGINT, TEST VARCHAR(100), PRIMARY KEY(id, ORDER_KEY))
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 (id BIGINT, ORDER_KEY BIGINT, TEST VARCHAR(100), PRIMARY KEY(id, ORDER_KEY));
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE IF EXISTS dummy_entity;
|
||||
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
DROP TABLE IF EXISTS dummy_entity2;
|
||||
CREATE TABLE dummy_entity2 (id BIGINT, ORDER_KEY BIGINT, TEST VARCHAR(100), CONSTRAINT dummym_entity2_pk PRIMARY KEY(id, ORDER_KEY));
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 (id BIGINT, ORDER_KEY BIGINT, TEST VARCHAR(100), PRIMARY KEY(id, ORDER_KEY));
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE dummy_entity;
|
||||
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
DROP TABLE dummy_entity2;
|
||||
CREATE TABLE dummy_entity2 (id BIGINT, ORDER_KEY BIGINT, TEST VARCHAR(100), PRIMARY KEY (id, ORDER_KEY));
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100))
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100));
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE IF EXISTS dummy_entity;
|
||||
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
DROP TABLE IF EXISTS dummy_entity2;
|
||||
CREATE TABLE dummy_entity2 (id BIGINT PRIMARY KEY, TEST VARCHAR(100));
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
CREATE TABLE dummy_entity2 (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100));
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE dummy_entity;
|
||||
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX_TEST VARCHAR(100));
|
||||
DROP TABLE dummy_entity2;
|
||||
CREATE TABLE dummy_entity2 (id SERIAL PRIMARY KEY, TEST VARCHAR(100));
|
||||
@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public class RelationalEntityDeleteWriter implements EntityWriter<Object, AggregateChange<?>> {
|
||||
|
||||
@@ -66,6 +67,7 @@ public class RelationalEntityDeleteWriter implements EntityWriter<Object, Aggreg
|
||||
List<DbAction<?>> actions = new ArrayList<>();
|
||||
|
||||
context.findPersistentPropertyPaths(entityType, PersistentProperty::isEntity)
|
||||
.filter(p -> !p.getRequiredLeafProperty().isEmbedded())
|
||||
.forEach(p -> actions.add(new DbAction.DeleteAll<>(p)));
|
||||
|
||||
Collections.reverse(actions);
|
||||
@@ -95,6 +97,7 @@ public class RelationalEntityDeleteWriter implements EntityWriter<Object, Aggreg
|
||||
List<DbAction<?>> actions = new ArrayList<>();
|
||||
|
||||
context.findPersistentPropertyPaths(aggregateChange.getEntityType(), PersistentProperty::isEntity)
|
||||
.filter(p -> !p.getRequiredLeafProperty().isEmbedded())
|
||||
.forEach(p -> actions.add(new DbAction.Delete<>(id, p)));
|
||||
|
||||
Collections.reverse(actions);
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.relational.core.conversion;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
@@ -30,11 +29,13 @@ 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.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
class WritingContext {
|
||||
|
||||
@@ -52,7 +53,7 @@ class WritingContext {
|
||||
this.root = root;
|
||||
this.entity = aggregateChange.getEntity();
|
||||
this.entityType = aggregateChange.getEntityType();
|
||||
this.paths = context.findPersistentPropertyPaths(entityType, PersistentProperty::isEntity);
|
||||
this.paths = context.findPersistentPropertyPaths(entityType, (p) -> p.isEntity() && !p.isEmbedded());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,20 +121,18 @@ class WritingContext {
|
||||
List<DbAction<?>> actions = new ArrayList<>();
|
||||
|
||||
from(path).forEach(node -> {
|
||||
DbAction.Insert<Object> insert;
|
||||
if (node.getPath().getRequiredLeafProperty().isQualified()) {
|
||||
|
||||
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());
|
||||
|
||||
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);
|
||||
} else {
|
||||
insert = new DbAction.Insert<>(node.getValue(), path, getAction(node.getParent()));
|
||||
}
|
||||
previousActions.put(node, insert);
|
||||
actions.add(insert);
|
||||
});
|
||||
|
||||
return actions;
|
||||
@@ -192,13 +191,9 @@ class WritingContext {
|
||||
|
||||
List<PathNode> nodes = new ArrayList<>();
|
||||
|
||||
if (path.getLength() == 1) {
|
||||
|
||||
Object value = context //
|
||||
.getRequiredPersistentEntity(entityType) //
|
||||
.getPropertyAccessor(entity) //
|
||||
.getProperty(path.getRequiredLeafProperty());
|
||||
if (dependsOnRootIgnoringEmbeddables(path)) {
|
||||
|
||||
Object value = getFromRootValue(path);
|
||||
nodes.addAll(createNodes(path, null, value));
|
||||
|
||||
} else {
|
||||
@@ -218,6 +213,44 @@ class WritingContext {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private boolean dependsOnRootIgnoringEmbeddables(PersistentPropertyPath<RelationalPersistentProperty> path){
|
||||
PersistentPropertyPath<RelationalPersistentProperty> currentPath = path.getParentPath();
|
||||
|
||||
while (!currentPath.isEmpty()){
|
||||
if(!currentPath.getRequiredLeafProperty().isEmbedded()){
|
||||
return false;
|
||||
}
|
||||
currentPath = currentPath.getParentPath();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@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 List<PathNode> createNodes(
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path,
|
||||
@Nullable PathNode parentNode, @Nullable Object value) {
|
||||
@@ -227,8 +260,9 @@ class WritingContext {
|
||||
}
|
||||
|
||||
List<PathNode> nodes = new ArrayList<>();
|
||||
|
||||
if (path.getRequiredLeafProperty().isQualified()) {
|
||||
if(path.getRequiredLeafProperty().isEmbedded()){
|
||||
nodes.add(new PathNode(path, parentNode, value));
|
||||
} else if (path.getRequiredLeafProperty().isQualified()) {
|
||||
|
||||
if (path.getRequiredLeafProperty().isMap()) {
|
||||
((Map<?, ?>) value)
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @author Florian Lüdiger
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public class BasicRelationalPersistentProperty extends AnnotationBasedPersistentProperty<RelationalPersistentProperty>
|
||||
implements RelationalPersistentProperty {
|
||||
@@ -56,6 +57,8 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
|
||||
private final RelationalMappingContext context;
|
||||
private final Lazy<Optional<String>> columnName;
|
||||
private final Lazy<Optional<String>> keyColumnName;
|
||||
private final Lazy<Boolean> isEmbedded;
|
||||
private final Lazy<String> embeddedPrefix;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationBasedPersistentProperty}.
|
||||
@@ -74,6 +77,17 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
|
||||
|
||||
this.context = context;
|
||||
|
||||
this.isEmbedded = Lazy.of(() -> Optional.ofNullable(
|
||||
findAnnotation(Embedded.class))
|
||||
.isPresent()
|
||||
);
|
||||
|
||||
this.embeddedPrefix = Lazy.of(() -> Optional.ofNullable(
|
||||
findAnnotation(Embedded.class))
|
||||
.map(Embedded::value)
|
||||
.orElse("")
|
||||
);
|
||||
|
||||
this.columnName = Lazy.of(() -> Optional.ofNullable( //
|
||||
findAnnotation(Column.class)) //
|
||||
.map(Column::value) //
|
||||
@@ -168,7 +182,21 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
|
||||
return isListLike();
|
||||
}
|
||||
|
||||
private boolean isListLike() {
|
||||
@Override
|
||||
public boolean isEmbedded() {
|
||||
return isEmbedded.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmbeddedPrefix() {
|
||||
if(isEmbedded()){
|
||||
return embeddedPrefix.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isListLike() {
|
||||
return isCollectionLike() && !Set.class.isAssignableFrom(this.getType());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.springframework.data.relational.core.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The annotation to configure a value object as embedded in the current table.
|
||||
*
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Documented
|
||||
public @interface Embedded {
|
||||
/**
|
||||
* @return prefix for columns in the embedded value object. Default is an empty String
|
||||
*/
|
||||
String value() default "";
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public interface RelationalPersistentProperty extends PersistentProperty<RelationalPersistentProperty> {
|
||||
|
||||
@@ -68,4 +69,15 @@ public interface RelationalPersistentProperty extends PersistentProperty<Relatio
|
||||
* Returns whether this property is an ordered property.
|
||||
*/
|
||||
boolean isOrdered();
|
||||
|
||||
/**
|
||||
* @return true, if the Property is an embedded value object, otherwise false.
|
||||
*/
|
||||
boolean isEmbedded();
|
||||
|
||||
/**
|
||||
* @return Prefix for embedded columns. If the column is not embedded the return value is null.
|
||||
*/
|
||||
@Nullable
|
||||
String getEmbeddedPrefix();
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ import org.springframework.data.relational.core.conversion.DbAction.Delete;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Insert;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.InsertRoot;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.UpdateRoot;
|
||||
import org.springframework.data.relational.core.mapping.Embedded;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link RelationalEntityWriter}
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RelationalEntityWriterUnitTests {
|
||||
@@ -65,6 +67,25 @@ public class RelationalEntityWriterUnitTests {
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void newEntityGetsConvertedToOneInsertByEmbeddedEntities() {
|
||||
|
||||
EmbeddedReferenceEntity entity = new EmbeddedReferenceEntity(null);
|
||||
entity.other = new Element(2L);
|
||||
|
||||
AggregateChange<EmbeddedReferenceEntity> aggregateChange = //
|
||||
new AggregateChange<>(Kind.SAVE, EmbeddedReferenceEntity.class, entity);
|
||||
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, DbActionTestSupport::extractPath, DbActionTestSupport::actualEntityType,
|
||||
DbActionTestSupport::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(InsertRoot.class, EmbeddedReferenceEntity.class, "", EmbeddedReferenceEntity.class, false) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
public void newEntityWithReferenceGetsConvertedToTwoInserts() {
|
||||
|
||||
@@ -417,6 +438,13 @@ public class RelationalEntityWriterUnitTests {
|
||||
String name;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class EmbeddedReferenceEntity {
|
||||
|
||||
@Id final Long id;
|
||||
@Embedded("prefix_") Element other;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class ReferenceWoIdEntity {
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.data.mapping.PropertyHandler;
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
* @author Florian Lüdiger
|
||||
* @author Bastian Wilhelm
|
||||
*/
|
||||
public class BasicRelationalPersistentPropertyUnitTests {
|
||||
|
||||
@@ -99,6 +100,26 @@ public class BasicRelationalPersistentPropertyUnitTests {
|
||||
assertThat(listProperty.getKeyColumn()).isEqualTo("dummy_key_column_name");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void detectsEmbeddedEntity() {
|
||||
|
||||
final RelationalPersistentEntity<?> requiredPersistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
|
||||
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("someList").isEmbedded()).isFalse();
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("someList").getEmbeddedPrefix()).isNull();
|
||||
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("id").isEmbedded()).isFalse();
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("id").getEmbeddedPrefix()).isNull();
|
||||
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("embeddableEntity").isEmbedded()).isTrue();
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("embeddableEntity").getEmbeddedPrefix()).isEmpty();
|
||||
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("prefixedEmbeddableEntity").isEmbedded()).isTrue();
|
||||
assertThat(requiredPersistentEntity.getRequiredPersistentProperty("prefixedEmbeddableEntity").getEmbeddedPrefix()).isEqualTo("prefix");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void checkTargetType(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity,
|
||||
String propertyName, Class<?> expected) {
|
||||
|
||||
@@ -123,6 +144,13 @@ public class BasicRelationalPersistentPropertyUnitTests {
|
||||
// DATACMNS-106
|
||||
private @Column("dummy_name") String name;
|
||||
|
||||
// DATAJDBC-111
|
||||
private @Embedded EmbeddableEntity embeddableEntity;
|
||||
|
||||
// DATAJDBC-111
|
||||
private @Embedded("prefix") EmbeddableEntity prefixedEmbeddableEntity;
|
||||
|
||||
|
||||
@Column("dummy_last_updated_at")
|
||||
public LocalDateTime getLocalDateTime() {
|
||||
return localDateTime;
|
||||
@@ -141,4 +169,10 @@ public class BasicRelationalPersistentPropertyUnitTests {
|
||||
private enum SomeEnum {
|
||||
ALPHA
|
||||
}
|
||||
|
||||
// DATAJDBC-111
|
||||
@Data
|
||||
private static class EmbeddableEntity{
|
||||
private final String embeddedTest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +120,11 @@ The properties of the following types are currently supported:
|
||||
|
||||
* Anything your database driver accepts.
|
||||
|
||||
* References to other entities. They are considered a one-to-one relationship.
|
||||
It is optional for such entities to have an `id` attribute.
|
||||
* References to other entities. They are considered a one-to-one relationship, or an embedded type.
|
||||
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`.
|
||||
|
||||
* `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.
|
||||
@@ -271,6 +272,34 @@ public class MySubEntity {
|
||||
----
|
||||
====
|
||||
|
||||
[[jdbc.entity-persistence.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.
|
||||
The consequence of this is, that in the database a table `my_entity` with the two columns `id` and `name` (from the `EmbeddedEntity` class) is expected.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public class MyEntity {
|
||||
@Id
|
||||
Integer id;
|
||||
|
||||
@Embedded
|
||||
EmbeddedEntity embeddedEntity;
|
||||
}
|
||||
|
||||
public class EmbeddedEntity {
|
||||
String name;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
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