Introduce AggregatePath.
AggregatePath replaces PersistentPropertyPathExtension. It gets created and cached by the RelationalMappingContext, which should be more efficient and certainly looks nicer. Closes #1525 Original pull request #1486
This commit is contained in:
@@ -15,16 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -38,11 +29,12 @@ import org.springframework.data.jdbc.core.convert.JdbcIdentifierBuilder;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPathAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.DbActionExecutionResult;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
@@ -65,7 +57,7 @@ class JdbcAggregateChangeExecutionContext {
|
||||
private static final String UPDATE_FAILED = "Failed to update entity [%s]; Id [%s] not found in database";
|
||||
private static final String UPDATE_FAILED_OPTIMISTIC_LOCKING = "Failed to update entity [%s]; The entity was updated since it was rea or it isn't in the database at all";
|
||||
|
||||
private final MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context;
|
||||
private final RelationalMappingContext context;
|
||||
private final JdbcConverter converter;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
|
||||
@@ -184,12 +176,11 @@ class JdbcAggregateChangeExecutionContext {
|
||||
Object id = getParentId(action);
|
||||
|
||||
JdbcIdentifierBuilder identifier = JdbcIdentifierBuilder //
|
||||
.forBackReferences(converter, new PersistentPropertyPathExtension(context, action.getPropertyPath()), id);
|
||||
.forBackReferences(converter, context.getAggregatePath(action.getPropertyPath()), id);
|
||||
|
||||
for (Map.Entry<PersistentPropertyPath<RelationalPersistentProperty>, Object> qualifier : action.getQualifiers()
|
||||
.entrySet()) {
|
||||
identifier = identifier.withQualifier(new PersistentPropertyPathExtension(context, qualifier.getKey()),
|
||||
qualifier.getValue());
|
||||
identifier = identifier.withQualifier(context.getAggregatePath(qualifier.getKey()), qualifier.getValue());
|
||||
}
|
||||
|
||||
return identifier.build();
|
||||
@@ -197,26 +188,22 @@ class JdbcAggregateChangeExecutionContext {
|
||||
|
||||
private Object getParentId(DbAction.WithDependingOn<?> action) {
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, action.getPropertyPath());
|
||||
PersistentPropertyPathExtension idPath = path.getIdDefiningParentPath();
|
||||
|
||||
DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action, idPath);
|
||||
DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action, context.getAggregatePath(action.getPropertyPath()).getIdDefiningParentPath());
|
||||
|
||||
return getPotentialGeneratedIdFrom(idOwningAction);
|
||||
}
|
||||
|
||||
private DbAction.WithEntity<?> getIdOwningAction(DbAction.WithEntity<?> action,
|
||||
PersistentPropertyPathExtension idPath) {
|
||||
private DbAction.WithEntity<?> getIdOwningAction(DbAction.WithEntity<?> action, AggregatePath idPath) {
|
||||
|
||||
if (!(action instanceof DbAction.WithDependingOn<?> withDependingOn)) {
|
||||
|
||||
Assert.state(idPath.getLength() == 0,
|
||||
Assert.state(idPath.isRoot(),
|
||||
"When the id path is not empty the id providing action should be of type WithDependingOn");
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
if (idPath.matches(withDependingOn.getPropertyPath())) {
|
||||
if (idPath.equals(context.getAggregatePath(withDependingOn.getPropertyPath()))) {
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
|
||||
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
@@ -86,14 +87,14 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a
|
||||
* {@link JdbcTypeFactory#unsupported() no-op type factory} throwing {@link UnsupportedOperationException} on type
|
||||
* creation. Use
|
||||
* {@link #BasicJdbcConverter(MappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
|
||||
* {@link #BasicJdbcConverter(RelationalMappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
|
||||
* (MappingContext, RelationResolver, JdbcTypeFactory)} to convert arrays and large objects into JDBC-specific types.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
RelationalMappingContext context,
|
||||
RelationResolver relationResolver) {
|
||||
|
||||
super(context, new JdbcCustomConversions());
|
||||
@@ -116,7 +117,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
* @since 2.0
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
RelationalMappingContext context,
|
||||
RelationResolver relationResolver, CustomConversions conversions, JdbcTypeFactory typeFactory,
|
||||
IdentifierProcessing identifierProcessing) {
|
||||
|
||||
@@ -300,12 +301,13 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
@Override
|
||||
public <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key) {
|
||||
return new ReadingContext<T>(new PersistentPropertyPathExtension(getMappingContext(), entity),
|
||||
return new ReadingContext<T>(getMappingContext().getAggregatePath( entity),
|
||||
new ResultSetAccessor(resultSet), Identifier.empty(), key).mapRow();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key) {
|
||||
public <T> T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key) {
|
||||
return new ReadingContext<T>(path, new ResultSetAccessor(resultSet), identifier, key).mapRow();
|
||||
}
|
||||
|
||||
@@ -350,8 +352,8 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
private final RelationalPersistentEntity<T> entity;
|
||||
|
||||
private final PersistentPropertyPathExtension rootPath;
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final AggregatePath rootPath;
|
||||
private final AggregatePath path;
|
||||
private final Identifier identifier;
|
||||
private final Object key;
|
||||
|
||||
@@ -360,7 +362,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
private final ResultSetAccessor accessor;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetAccessor accessor, Identifier identifier,
|
||||
private ReadingContext(AggregatePath rootPath, ResultSetAccessor accessor, Identifier identifier,
|
||||
Object key) {
|
||||
RelationalPersistentEntity<T> entity = (RelationalPersistentEntity<T>) rootPath.getLeafEntity();
|
||||
|
||||
@@ -368,7 +370,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
this.entity = entity;
|
||||
this.rootPath = rootPath;
|
||||
this.path = new PersistentPropertyPathExtension(getMappingContext(), this.entity);
|
||||
this.path = getMappingContext().getAggregatePath( this.entity);
|
||||
this.identifier = identifier;
|
||||
this.key = key;
|
||||
this.propertyValueProvider = new JdbcPropertyValueProvider(path, accessor);
|
||||
@@ -376,10 +378,11 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
private ReadingContext(RelationalPersistentEntity<T> entity, PersistentPropertyPathExtension rootPath,
|
||||
PersistentPropertyPathExtension path, Identifier identifier, Object key,
|
||||
private ReadingContext(RelationalPersistentEntity<T> entity, AggregatePath rootPath,
|
||||
AggregatePath path, Identifier identifier, Object key,
|
||||
JdbcPropertyValueProvider propertyValueProvider,
|
||||
JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider, ResultSetAccessor accessor) {
|
||||
|
||||
this.entity = entity;
|
||||
this.rootPath = rootPath;
|
||||
this.path = path;
|
||||
@@ -393,7 +396,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
private <S> ReadingContext<S> extendBy(RelationalPersistentProperty property) {
|
||||
return new ReadingContext<>(
|
||||
(RelationalPersistentEntity<S>) getMappingContext().getRequiredPersistentEntity(property.getActualType()),
|
||||
rootPath.extendBy(property), path.extendBy(property), identifier, key,
|
||||
rootPath.append(property), path.append(property), identifier, key,
|
||||
propertyValueProvider.extendBy(property), backReferencePropertyValueProvider.extendBy(property), accessor);
|
||||
}
|
||||
|
||||
@@ -453,10 +456,10 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
private Iterable<Object> resolveRelation(@Nullable Object id, RelationalPersistentProperty property) {
|
||||
|
||||
Identifier identifier = id == null //
|
||||
? this.identifier.withPart(rootPath.getQualifierColumn(), key, Object.class) //
|
||||
: Identifier.of(rootPath.extendBy(property).getReverseColumnName(), id, Object.class);
|
||||
? this.identifier.withPart(rootPath.getTableInfo().qualifierColumnInfo().name(), key, Object.class) //
|
||||
: Identifier.of(rootPath.append(property).getTableInfo().reverseColumnInfo().name(), id, Object.class);
|
||||
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath = path.extendBy(property)
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath = path.append(property)
|
||||
.getRequiredPersistentPropertyPath();
|
||||
|
||||
return relationResolver.findAllByPath(identifier, propertyPath);
|
||||
|
||||
@@ -28,12 +28,12 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -297,8 +297,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
Assert.notNull(identifier, "identifier must not be null");
|
||||
Assert.notNull(propertyPath, "propertyPath must not be null");
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, propertyPath);
|
||||
Class<?> actualType = path.getActualType();
|
||||
AggregatePath path = context.getAggregatePath(propertyPath);
|
||||
Class<?> actualType = path.getLeafEntity().getType();
|
||||
|
||||
String findAllByProperty = sql(actualType) //
|
||||
.getFindAllByProperty(identifier, propertyPath);
|
||||
@@ -339,8 +339,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
String sqlQuery = sql(domainType).selectByQuery(query, parameterSource);
|
||||
|
||||
try {
|
||||
return Optional.ofNullable(
|
||||
operations.queryForObject(sqlQuery, parameterSource, getEntityRowMapper(domainType)));
|
||||
return Optional.ofNullable(operations.queryForObject(sqlQuery, parameterSource, getEntityRowMapper(domainType)));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -394,14 +393,15 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), converter);
|
||||
}
|
||||
|
||||
private EntityRowMapper<?> getEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
|
||||
private EntityRowMapper<?> getEntityRowMapper(AggregatePath path, Identifier identifier) {
|
||||
return new EntityRowMapper<>(path, converter, identifier);
|
||||
}
|
||||
|
||||
private RowMapper<?> getMapEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
|
||||
private RowMapper<?> getMapEntityRowMapper(AggregatePath path, Identifier identifier) {
|
||||
|
||||
SqlIdentifier keyColumn = path.getQualifierColumn();
|
||||
Assert.notNull(keyColumn, () -> "KeyColumn must not be null for " + path);
|
||||
AggregatePath.ColumnInfo qualifierColumnInfo = path.getTableInfo().qualifierColumnInfo();
|
||||
Assert.notNull(qualifierColumnInfo, () -> "Qualifier column must not be null for " + path);
|
||||
SqlIdentifier keyColumn = qualifierColumnInfo.name();
|
||||
|
||||
return new MapEntityRowMapper<>(path, converter, identifier, keyColumn);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -35,13 +36,28 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
private final RelationalPersistentEntity<T> entity;
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final AggregatePath path;
|
||||
private final JdbcConverter converter;
|
||||
private final Identifier identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @deprecated use {@link EntityRowMapper#EntityRowMapper(AggregatePath, JdbcConverter, Identifier)} instead
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier) {
|
||||
|
||||
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
|
||||
this.path = path.getAggregatePath();
|
||||
this.converter = converter;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityRowMapper(AggregatePath path, JdbcConverter converter, Identifier identifier) {
|
||||
|
||||
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
|
||||
/**
|
||||
* {@link PropertyValueProvider} obtaining values from a {@link ResultSetAccessor}. For a given id property it provides
|
||||
@@ -31,14 +30,14 @@ import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
*/
|
||||
class JdbcBackReferencePropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {
|
||||
|
||||
private final PersistentPropertyPathExtension basePath;
|
||||
private final AggregatePath basePath;
|
||||
private final ResultSetAccessor resultSet;
|
||||
|
||||
/**
|
||||
* @param basePath path from the aggregate root relative to which all properties get resolved.
|
||||
* @param resultSet the {@link ResultSetAccessor} from which to obtain the actual values.
|
||||
*/
|
||||
JdbcBackReferencePropertyValueProvider(PersistentPropertyPathExtension basePath, ResultSetAccessor resultSet) {
|
||||
JdbcBackReferencePropertyValueProvider(AggregatePath basePath, ResultSetAccessor resultSet) {
|
||||
|
||||
this.resultSet = resultSet;
|
||||
this.basePath = basePath;
|
||||
@@ -46,10 +45,10 @@ class JdbcBackReferencePropertyValueProvider implements PropertyValueProvider<Re
|
||||
|
||||
@Override
|
||||
public <T> T getPropertyValue(RelationalPersistentProperty property) {
|
||||
return (T) resultSet.getObject(basePath.extendBy(property).getReverseColumnNameAlias().getReference());
|
||||
return (T) resultSet.getObject(basePath.append(property).getTableInfo().reverseColumnInfo().alias().getReference());
|
||||
}
|
||||
|
||||
public JdbcBackReferencePropertyValueProvider extendBy(RelationalPersistentProperty property) {
|
||||
return new JdbcBackReferencePropertyValueProvider(basePath.extendBy(property), resultSet);
|
||||
return new JdbcBackReferencePropertyValueProvider(basePath.append(property), resultSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLType;
|
||||
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcValue;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -67,8 +70,24 @@ public interface JdbcConverter extends RelationalConverter {
|
||||
* @param key primary key.
|
||||
* @param <T>
|
||||
* @return
|
||||
* @deprecated use {@link #mapRow(AggregatePath, ResultSet, Identifier, Object)} instead.
|
||||
*/
|
||||
<T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key);
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
default <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key){
|
||||
return mapRow(path.getAggregatePath(), resultSet, identifier, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the current row from {@link ResultSet} to an {@link AggregatePath#getLeafEntity()} entity}.
|
||||
*
|
||||
* @param path path to the owning property.
|
||||
* @param resultSet the {@link ResultSet} to read from.
|
||||
* @param identifier entity identifier.
|
||||
* @param key primary key.
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
<T> T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key);
|
||||
|
||||
/**
|
||||
* The type to be used to store this property in the database. Multidimensional arrays are unwrapped to reflect a
|
||||
@@ -88,4 +107,7 @@ public interface JdbcConverter extends RelationalConverter {
|
||||
* @since 2.0
|
||||
*/
|
||||
SQLType getTargetSqlType(RelationalPersistentProperty property);
|
||||
|
||||
@Override
|
||||
RelationalMappingContext getMappingContext();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,12 +40,23 @@ public class JdbcIdentifierBuilder {
|
||||
|
||||
/**
|
||||
* Creates ParentKeys with backreference for the given path and value of the parents id.
|
||||
*
|
||||
* @deprecated Use {@link #forBackReferences(JdbcConverter, AggregatePath, Object)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, PersistentPropertyPathExtension path,
|
||||
@Nullable Object value) {
|
||||
return forBackReferences(converter, path.getAggregatePath(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates ParentKeys with backreference for the given path and value of the parents id.
|
||||
*/
|
||||
public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, AggregatePath path,
|
||||
@Nullable Object value) {
|
||||
|
||||
Identifier identifier = Identifier.of( //
|
||||
path.getReverseColumnName(), //
|
||||
path.getTableInfo().reverseColumnInfo().name(), //
|
||||
value, //
|
||||
converter.getColumnType(path.getIdDefiningParentPath().getRequiredIdProperty()) //
|
||||
);
|
||||
@@ -59,12 +71,26 @@ public class JdbcIdentifierBuilder {
|
||||
* @param value map key or list index qualifying the map identified by {@code path}. Must not be {@literal null}.
|
||||
* @return this builder. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Deprecated
|
||||
public JdbcIdentifierBuilder withQualifier(PersistentPropertyPathExtension path, Object value) {
|
||||
|
||||
return withQualifier(path.getAggregatePath(), value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a qualifier to the identifier to build. A qualifier is a map key or a list index.
|
||||
*
|
||||
* @param path path to the map that gets qualified by {@code value}. Must not be {@literal null}.
|
||||
* @param value map key or list index qualifying the map identified by {@code path}. Must not be {@literal null}.
|
||||
* @return this builder. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
public JdbcIdentifierBuilder withQualifier(AggregatePath path, Object value) {
|
||||
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(value, "Value must not be null");
|
||||
|
||||
identifier = identifier.withPart(path.getQualifierColumn(), value, path.getQualifierColumnType());
|
||||
identifier = identifier.withPart(path.getTableInfo().qualifierColumnInfo().name(), value, path.getTableInfo().qualifierColumnType());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
|
||||
/**
|
||||
* {@link PropertyValueProvider} obtaining values from a {@link ResultSetAccessor}.
|
||||
@@ -29,15 +28,14 @@ import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
*/
|
||||
class JdbcPropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {
|
||||
|
||||
private final PersistentPropertyPathExtension basePath;
|
||||
private final AggregatePath basePath;
|
||||
private final ResultSetAccessor resultSet;
|
||||
|
||||
/**
|
||||
* @param basePath path from the aggregate root relative to which all properties get resolved.
|
||||
* @param resultSet the {@link ResultSetAccessor} from which to obtain the actual values.
|
||||
*/
|
||||
JdbcPropertyValueProvider(PersistentPropertyPathExtension basePath,
|
||||
ResultSetAccessor resultSet) {
|
||||
JdbcPropertyValueProvider(AggregatePath basePath, ResultSetAccessor resultSet) {
|
||||
|
||||
this.resultSet = resultSet;
|
||||
this.basePath = basePath;
|
||||
@@ -59,10 +57,11 @@ class JdbcPropertyValueProvider implements PropertyValueProvider<RelationalPersi
|
||||
}
|
||||
|
||||
private String getColumnName(RelationalPersistentProperty property) {
|
||||
return basePath.extendBy(property).getColumnAlias().getReference();
|
||||
AggregatePath.ColumnInfo columnInfo = basePath.append(property).getColumnInfo();
|
||||
return columnInfo.alias().getReference();
|
||||
}
|
||||
|
||||
public JdbcPropertyValueProvider extendBy(RelationalPersistentProperty property) {
|
||||
return new JdbcPropertyValueProvider(basePath.extendBy(property), resultSet);
|
||||
return new JdbcPropertyValueProvider(basePath.append(property), resultSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -35,12 +36,13 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
*/
|
||||
class MapEntityRowMapper<T> implements RowMapper<Map.Entry<Object, T>> {
|
||||
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final AggregatePath path;
|
||||
private final JdbcConverter converter;
|
||||
private final Identifier identifier;
|
||||
private final SqlIdentifier keyColumn;
|
||||
|
||||
MapEntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier, SqlIdentifier keyColumn) {
|
||||
MapEntityRowMapper(AggregatePath path, JdbcConverter converter, Identifier identifier, SqlIdentifier keyColumn) {
|
||||
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
this.identifier = identifier;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -52,18 +52,20 @@ class SqlContext {
|
||||
return table;
|
||||
}
|
||||
|
||||
Table getTable(PersistentPropertyPathExtension path) {
|
||||
Table getTable(AggregatePath path) {
|
||||
|
||||
SqlIdentifier tableAlias = path.getTableAlias();
|
||||
Table table = Table.create(path.getQualifiedTableName());
|
||||
SqlIdentifier tableAlias = path.getTableInfo().tableAlias();
|
||||
Table table = Table.create(path.getTableInfo().qualifiedTableName());
|
||||
return tableAlias == null ? table : table.as(tableAlias);
|
||||
}
|
||||
|
||||
Column getColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getColumnName()).as(path.getColumnAlias());
|
||||
Column getColumn(AggregatePath path) {
|
||||
AggregatePath.ColumnInfo columnInfo = path.getColumnInfo();
|
||||
AggregatePath.ColumnInfo columnInfo1 = path.getColumnInfo();
|
||||
return getTable(path).column(columnInfo1.name()).as(columnInfo.alias());
|
||||
}
|
||||
|
||||
Column getReverseColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getReverseColumnName()).as(path.getReverseColumnNameAlias());
|
||||
Column getReverseColumn(AggregatePath path) {
|
||||
return getTable(path).column(path.getTableInfo().reverseColumnInfo().name()).as(path.getTableInfo().reverseColumnInfo().alias());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.RenderContextFactory;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -66,8 +66,13 @@ class SqlGenerator {
|
||||
static final SqlIdentifier IDS_SQL_PARAMETER = SqlIdentifier.unquoted("ids");
|
||||
static final SqlIdentifier ROOT_ID_PARAMETER = SqlIdentifier.unquoted("rootId");
|
||||
|
||||
/**
|
||||
* Length of an aggregate path that is one longer then the root path.
|
||||
*/
|
||||
private static final int FIRST_NON_ROOT_LENTH = 2;
|
||||
|
||||
private final RelationalPersistentEntity<?> entity;
|
||||
private final MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
|
||||
private final RelationalMappingContext mappingContext;
|
||||
private final RenderContext renderContext;
|
||||
|
||||
private final SqlContext sqlContext;
|
||||
@@ -112,6 +117,40 @@ class SqlGenerator {
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* When deleting entities there is a fundamental difference between deleting
|
||||
* <ol>
|
||||
* <li>the aggregate root.</li>
|
||||
* <li>a first level entity which still references the root id directly</li>
|
||||
* <li>and all other entities which have to use a subselect to navigate from the id of the aggregate root to something
|
||||
* referenced by the table in question.</li>
|
||||
* </ol>
|
||||
* For paths of the second kind this method returns {@literal true}.
|
||||
*
|
||||
* @param path the path to analyze.
|
||||
* @return If the given path is considered deeply nested.
|
||||
*/
|
||||
private static boolean isFirstNonRoot(AggregatePath path) {
|
||||
return path.getLength() == FIRST_NON_ROOT_LENTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* When deleting entities there is a fundamental difference between deleting
|
||||
* <ol>
|
||||
* <li>the aggregate root.</li>
|
||||
* <li>a first level entity which still references the root id directly</li>
|
||||
* <li>and all other entities which have to use a subselect to navigate from the id of the aggregate root to something
|
||||
* referenced by the table in question.</li>
|
||||
* </ol>
|
||||
* For paths of the third kind this method returns {@literal true}.
|
||||
*
|
||||
* @param path the path to analyze.
|
||||
* @return If the given path is considered deeply nested.
|
||||
*/
|
||||
private static boolean isDeeplyNested(AggregatePath path) {
|
||||
return path.getLength() > FIRST_NON_ROOT_LENTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an IN-condition based on a {@link Select Sub-Select} which selects the ids (or stand-ins for ids) of the
|
||||
* given {@literal path} to those that reference the root entities specified by the {@literal rootCondition}.
|
||||
@@ -121,25 +160,25 @@ class SqlGenerator {
|
||||
* @param filterColumn the column to apply the IN-condition to.
|
||||
* @return the IN condition
|
||||
*/
|
||||
private Condition getSubselectCondition(PersistentPropertyPathExtension path,
|
||||
Function<Column, Condition> rootCondition, Column filterColumn) {
|
||||
private Condition getSubselectCondition(AggregatePath path, Function<Column, Condition> rootCondition,
|
||||
Column filterColumn) {
|
||||
|
||||
PersistentPropertyPathExtension parentPath = path.getParentPath();
|
||||
AggregatePath parentPath = path.getParentPath();
|
||||
|
||||
if (!parentPath.hasIdProperty()) {
|
||||
if (parentPath.getLength() > 1) {
|
||||
if (isDeeplyNested(parentPath)) {
|
||||
return getSubselectCondition(parentPath, rootCondition, filterColumn);
|
||||
}
|
||||
return rootCondition.apply(filterColumn);
|
||||
}
|
||||
|
||||
Table subSelectTable = Table.create(parentPath.getQualifiedTableName());
|
||||
Column idColumn = subSelectTable.column(parentPath.getIdColumnName());
|
||||
Column selectFilterColumn = subSelectTable.column(parentPath.getEffectiveIdColumnName());
|
||||
Table subSelectTable = Table.create(parentPath.getTableInfo().qualifiedTableName());
|
||||
Column idColumn = subSelectTable.column(parentPath.getTableInfo().idColumnName());
|
||||
Column selectFilterColumn = subSelectTable.column(parentPath.getTableInfo().effectiveIdColumnName());
|
||||
|
||||
Condition innerCondition;
|
||||
|
||||
if (parentPath.getLength() == 1) { // if the parent is the root of the path
|
||||
if (isFirstNonRoot(parentPath)) { // if the parent is the root of the path
|
||||
|
||||
// apply the rootCondition
|
||||
innerCondition = rootCondition.apply(selectFilterColumn);
|
||||
@@ -216,9 +255,9 @@ class SqlGenerator {
|
||||
Assert.notNull(parentIdentifier, "identifier must not be null");
|
||||
Assert.notNull(propertyPath, "propertyPath must not be null");
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(mappingContext, propertyPath);
|
||||
AggregatePath path = mappingContext.getAggregatePath(propertyPath);
|
||||
|
||||
return getFindAllByProperty(parentIdentifier, path.getQualifierColumn(), path.isOrdered());
|
||||
return getFindAllByProperty(parentIdentifier, path.getTableInfo().qualifierColumnInfo(), path.isOrdered());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +272,8 @@ class SqlGenerator {
|
||||
* keyColumn must not be {@code null}.
|
||||
* @return a SQL String.
|
||||
*/
|
||||
String getFindAllByProperty(Identifier parentIdentifier, @Nullable SqlIdentifier keyColumn, boolean ordered) {
|
||||
String getFindAllByProperty(Identifier parentIdentifier, @Nullable AggregatePath.ColumnInfo keyColumn,
|
||||
boolean ordered) {
|
||||
|
||||
Assert.isTrue(keyColumn != null || !ordered,
|
||||
"If the SQL statement should be ordered a keyColumn to order by must be provided");
|
||||
@@ -243,14 +283,14 @@ class SqlGenerator {
|
||||
SelectBuilder.SelectWhere builder = selectBuilder( //
|
||||
keyColumn == null //
|
||||
? Collections.emptyList() //
|
||||
: Collections.singleton(keyColumn) //
|
||||
: Collections.singleton(keyColumn.name()) //
|
||||
);
|
||||
|
||||
Condition condition = buildConditionForBackReference(parentIdentifier, table);
|
||||
SelectBuilder.SelectWhereAndOr withWhereClause = builder.where(condition);
|
||||
|
||||
Select select = ordered //
|
||||
? withWhereClause.orderBy(table.column(keyColumn).as(keyColumn)).build() //
|
||||
? withWhereClause.orderBy(table.column(keyColumn.name()).as(keyColumn.alias())).build() //
|
||||
: withWhereClause.build();
|
||||
|
||||
return render(select);
|
||||
@@ -399,7 +439,7 @@ class SqlGenerator {
|
||||
return render(deleteAll.build());
|
||||
}
|
||||
|
||||
return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path), Column::isNotNull);
|
||||
return createDeleteByPathAndCriteria(mappingContext.getAggregatePath(path), Column::isNotNull);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,7 +450,7 @@ class SqlGenerator {
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
String createDeleteByPath(PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path),
|
||||
return createDeleteByPathAndCriteria(mappingContext.getAggregatePath(path),
|
||||
filterColumn -> filterColumn.isEqualTo(getBindMarker(ROOT_ID_PARAMETER)));
|
||||
}
|
||||
|
||||
@@ -423,7 +463,7 @@ class SqlGenerator {
|
||||
*/
|
||||
String createDeleteInByPath(PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
|
||||
return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path),
|
||||
return createDeleteByPathAndCriteria(mappingContext.getAggregatePath(path),
|
||||
filterColumn -> filterColumn.in(getBindMarker(IDS_SQL_PARAMETER)));
|
||||
}
|
||||
|
||||
@@ -480,7 +520,7 @@ class SqlGenerator {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : mappingContext
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(mappingContext, path);
|
||||
AggregatePath extPath = mappingContext.getAggregatePath(path);
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(extPath);
|
||||
@@ -537,13 +577,13 @@ class SqlGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Column} for {@link PersistentPropertyPathExtension}.
|
||||
* Create a {@link Column} for {@link AggregatePath}.
|
||||
*
|
||||
* @param path the path to the column in question.
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
Column getColumn(PersistentPropertyPathExtension path) {
|
||||
Column getColumn(AggregatePath path) {
|
||||
|
||||
// an embedded itself doesn't give a column, its members will though.
|
||||
// if there is a collection or map on the path it won't get selected at all, but it will get loaded with a separate
|
||||
@@ -572,7 +612,7 @@ class SqlGenerator {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Join getJoin(PersistentPropertyPathExtension path) {
|
||||
Join getJoin(AggregatePath path) {
|
||||
|
||||
if (!path.isEntity() || path.isEmbedded() || path.isMultiValued()) {
|
||||
return null;
|
||||
@@ -580,13 +620,13 @@ class SqlGenerator {
|
||||
|
||||
Table currentTable = sqlContext.getTable(path);
|
||||
|
||||
PersistentPropertyPathExtension idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
AggregatePath idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
Table parentTable = sqlContext.getTable(idDefiningParentPath);
|
||||
|
||||
return new Join( //
|
||||
currentTable, //
|
||||
currentTable.column(path.getReverseColumnName()), //
|
||||
parentTable.column(idDefiningParentPath.getIdColumnName()) //
|
||||
currentTable.column(path.getTableInfo().reverseColumnInfo().name()), //
|
||||
parentTable.column(idDefiningParentPath.getTableInfo().idColumnName()) //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -707,18 +747,17 @@ class SqlGenerator {
|
||||
.where(getIdColumn().in(getBindMarker(IDS_SQL_PARAMETER)));
|
||||
}
|
||||
|
||||
private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path,
|
||||
Function<Column, Condition> rootCondition) {
|
||||
private String createDeleteByPathAndCriteria(AggregatePath path, Function<Column, Condition> rootCondition) {
|
||||
|
||||
Table table = Table.create(path.getQualifiedTableName());
|
||||
Table table = Table.create(path.getTableInfo().qualifiedTableName());
|
||||
|
||||
DeleteBuilder.DeleteWhere builder = Delete.builder() //
|
||||
.from(table);
|
||||
Delete delete;
|
||||
|
||||
Column filterColumn = table.column(path.getReverseColumnName());
|
||||
Column filterColumn = table.column(path.getTableInfo().reverseColumnInfo().name());
|
||||
|
||||
if (path.getLength() == 1) {
|
||||
if (isFirstNonRoot(path)) {
|
||||
|
||||
delete = builder //
|
||||
.where(rootCondition.apply(filterColumn)) //
|
||||
@@ -926,10 +965,10 @@ class SqlGenerator {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : mappingContext
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(mappingContext, path);
|
||||
AggregatePath aggregatePath = mappingContext.getAggregatePath(path);
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(extPath);
|
||||
Join join = getJoin(aggregatePath);
|
||||
if (join != null) {
|
||||
baseSelect = baseSelect.leftOuterJoin(join.joinTable).on(join.joinColumn).equals(join.parentId);
|
||||
}
|
||||
@@ -960,7 +999,7 @@ class SqlGenerator {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : mappingContext
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(mappingContext, path);
|
||||
AggregatePath extPath = mappingContext.getAggregatePath(path);
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(extPath);
|
||||
|
||||
@@ -25,10 +25,9 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.QueryMapper;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.RenderContextFactory;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -117,8 +116,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
* @param tree the tree structure defining the predicate of the query.
|
||||
* @param parameters parameters for the predicate.
|
||||
*/
|
||||
static void validate(PartTree tree, Parameters<?, ?> parameters,
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context) {
|
||||
static void validate(PartTree tree, Parameters<?, ?> parameters, RelationalMappingContext context) {
|
||||
|
||||
RelationalQueryCreator.validate(tree, parameters);
|
||||
|
||||
@@ -127,30 +125,30 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath = context
|
||||
.getPersistentPropertyPath(part.getProperty());
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, propertyPath);
|
||||
AggregatePath path = context.getAggregatePath(propertyPath);
|
||||
|
||||
for (PersistentPropertyPathExtension pathToValidate = path; path.getLength() > 0; path = path.getParentPath()) {
|
||||
validateProperty(pathToValidate);
|
||||
}
|
||||
path.forEach(JdbcQueryCreator::validateProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateProperty(PersistentPropertyPathExtension path) {
|
||||
private static void validateProperty(AggregatePath path) {
|
||||
|
||||
if (!path.getParentPath().isEmbedded() && path.getLength() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot query by nested property: %s", path.getRequiredPersistentPropertyPath().toDotPath()));
|
||||
if (path.isRoot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.getParentPath().isEmbedded() && path.getLength() > 2) {
|
||||
throw new IllegalArgumentException(String.format("Cannot query by nested property: %s", path.toDotPath()));
|
||||
}
|
||||
|
||||
if (path.isMultiValued() || path.isMap()) {
|
||||
throw new IllegalArgumentException(String.format("Cannot query by multi-valued property: %s",
|
||||
path.getRequiredPersistentPropertyPath().getLeafProperty().getName()));
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot query by multi-valued property: %s", path.getRequiredLeafProperty().getName()));
|
||||
}
|
||||
|
||||
if (!path.isEmbedded() && path.isEntity()) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot query by nested entity: %s", path.getRequiredPersistentPropertyPath().toDotPath()));
|
||||
throw new IllegalArgumentException(String.format("Cannot query by nested entity: %s", path.toDotPath()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,22 +243,21 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : context
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(context, path);
|
||||
AggregatePath aggregatePath = context.getAggregatePath(path);
|
||||
|
||||
if (returnedType.needsCustomConstruction()) {
|
||||
if (!returnedType.getInputProperties()
|
||||
.contains(extPath.getRequiredPersistentPropertyPath().getBaseProperty().getName())) {
|
||||
if (!returnedType.getInputProperties().contains(aggregatePath.getRequiredBaseProperty().getName())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(sqlContext, extPath);
|
||||
Join join = getJoin(sqlContext, aggregatePath);
|
||||
if (join != null) {
|
||||
joinTables.add(join);
|
||||
}
|
||||
|
||||
Column column = getColumn(sqlContext, extPath);
|
||||
Column column = getColumn(sqlContext, aggregatePath);
|
||||
if (column != null) {
|
||||
columnExpressions.add(column);
|
||||
}
|
||||
@@ -277,14 +274,14 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Column} for {@link PersistentPropertyPathExtension}.
|
||||
* Create a {@link Column} for {@link AggregatePath}.
|
||||
*
|
||||
* @param sqlContext
|
||||
* @param path the path to the column in question.
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
private Column getColumn(SqlContext sqlContext, PersistentPropertyPathExtension path) {
|
||||
private Column getColumn(SqlContext sqlContext, AggregatePath path) {
|
||||
|
||||
// an embedded itself doesn't give an column, its members will though.
|
||||
// if there is a collection or map on the path it won't get selected at all, but it will get loaded with a separate
|
||||
@@ -313,7 +310,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Join getJoin(SqlContext sqlContext, PersistentPropertyPathExtension path) {
|
||||
Join getJoin(SqlContext sqlContext, AggregatePath path) {
|
||||
|
||||
if (!path.isEntity() || path.isEmbedded() || path.isMultiValued()) {
|
||||
return null;
|
||||
@@ -321,13 +318,13 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
|
||||
Table currentTable = sqlContext.getTable(path);
|
||||
|
||||
PersistentPropertyPathExtension idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
AggregatePath idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
Table parentTable = sqlContext.getTable(idDefiningParentPath);
|
||||
|
||||
return new Join( //
|
||||
currentTable, //
|
||||
currentTable.column(path.getReverseColumnName()), //
|
||||
parentTable.column(idDefiningParentPath.getIdColumnName()) //
|
||||
currentTable.column(path.getTableInfo().reverseColumnInfo().name()), //
|
||||
parentTable.column(idDefiningParentPath.getTableInfo().idColumnName()) //
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository.query;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -53,18 +53,21 @@ class SqlContext {
|
||||
return table;
|
||||
}
|
||||
|
||||
Table getTable(PersistentPropertyPathExtension path) {
|
||||
Table getTable(AggregatePath path) {
|
||||
|
||||
SqlIdentifier tableAlias = path.getTableAlias();
|
||||
Table table = Table.create(path.getQualifiedTableName());
|
||||
SqlIdentifier tableAlias = path.getTableInfo().tableAlias();
|
||||
Table table = Table.create(path.getTableInfo().qualifiedTableName());
|
||||
return tableAlias == null ? table : table.as(tableAlias);
|
||||
}
|
||||
|
||||
Column getColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getColumnName()).as(path.getColumnAlias());
|
||||
Column getColumn(AggregatePath path) {
|
||||
AggregatePath.ColumnInfo columnInfo = path.getColumnInfo();
|
||||
AggregatePath.ColumnInfo columnInfo1 = path.getColumnInfo();
|
||||
return getTable(path).column(columnInfo1.name()).as(columnInfo.alias());
|
||||
}
|
||||
|
||||
Column getReverseColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getReverseColumnName()).as(path.getReverseColumnNameAlias());
|
||||
Column getReverseColumn(AggregatePath path) {
|
||||
return getTable(path).column(path.getTableInfo().reverseColumnInfo().name())
|
||||
.as(path.getTableInfo().reverseColumnInfo().alias());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user