@@ -265,22 +265,6 @@ public interface JdbcAggregateOperations {
|
||||
*/
|
||||
<T> void delete(T aggregateRoot);
|
||||
|
||||
/**
|
||||
* Delete an aggregate identified by its aggregate root.
|
||||
*
|
||||
* @param aggregateRoot to delete. Must not be {@code null}.
|
||||
* @param domainType the type of the aggregate root. Must not be {@code null}.
|
||||
* @param <T> the type of the aggregate root.
|
||||
* @throws org.springframework.dao.OptimisticLockingFailureException when {@literal T} has a version attribute and the
|
||||
* version attribute of the provided entity does not match the version attribute in the database, or when
|
||||
* there is no aggregate root with matching id. In other cases a NOOP delete is silently ignored.
|
||||
* @deprecated since 3.0 use {@link #delete(Object)} instead
|
||||
*/
|
||||
@Deprecated(since = "3.0")
|
||||
default <T> void delete(T aggregateRoot, Class<T> domainType) {
|
||||
delete(aggregateRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all aggregates of a given type.
|
||||
*
|
||||
@@ -295,21 +279,4 @@ public interface JdbcAggregateOperations {
|
||||
* @param <T> the type of the aggregate roots.
|
||||
*/
|
||||
<T> void deleteAll(Iterable<? extends T> aggregateRoots);
|
||||
|
||||
/**
|
||||
* Delete all aggregates identified by their aggregate roots.
|
||||
*
|
||||
* @param aggregateRoots to delete. Must not be {@code null}.
|
||||
* @param domainType type of the aggregate roots to be deleted. Must not be {@code null}.
|
||||
* @param <T> the type of the aggregate roots.
|
||||
* @throws org.springframework.dao.OptimisticLockingFailureException when {@literal T} has a version attribute and for
|
||||
* at least on entity the version attribute of the entity does not match the version attribute in the
|
||||
* database, or when there is no aggregate root with matching id. In other cases a NOOP delete is silently
|
||||
* ignored.
|
||||
* @deprecated since 3.0 use {@link #deleteAll(Iterable)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.0")
|
||||
default <T> void deleteAll(Iterable<? extends T> aggregateRoots, Class<T> domainType) {
|
||||
deleteAll(aggregateRoots);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 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
|
||||
*
|
||||
* https://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.convert;
|
||||
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
|
||||
/**
|
||||
* {@link RelationalConverter} that uses a {@link MappingContext} to apply conversion of relational values to property
|
||||
* values.
|
||||
* <p>
|
||||
* Conversion is configurable by providing a customized {@link CustomConversions}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
* @deprecated since 3.2, use {@link MappingJdbcConverter} instead as the naming suggests a limited scope of
|
||||
* functionality.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
public class BasicJdbcConverter extends MappingJdbcConverter {
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicJdbcConverter} given {@link MappingContext} and a {@link JdbcTypeFactory#unsupported()
|
||||
* no-op type factory} throwing {@link UnsupportedOperationException} on type creation. Use
|
||||
* {@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(RelationalMappingContext context, RelationResolver relationResolver) {
|
||||
super(context, relationResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicJdbcConverter} given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
|
||||
* @param typeFactory must not be {@literal null}
|
||||
* @since 3.2
|
||||
*/
|
||||
public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
|
||||
CustomConversions conversions, JdbcTypeFactory typeFactory) {
|
||||
super(context, relationResolver, conversions, typeFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicJdbcConverter} given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
|
||||
* @param typeFactory must not be {@literal null}
|
||||
* @param identifierProcessing must not be {@literal null}
|
||||
* @since 2.0
|
||||
*/
|
||||
public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
|
||||
CustomConversions conversions, JdbcTypeFactory typeFactory, IdentifierProcessing identifierProcessing) {
|
||||
super(context, relationResolver, conversions, typeFactory);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2024 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
|
||||
*
|
||||
* https://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.convert;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Counterpart to {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} containing methods for
|
||||
* performing batch updates with generated keys.
|
||||
*
|
||||
* @author Chirag Tailor
|
||||
* @author Mark Paluch
|
||||
* @since 2.4
|
||||
* @deprecated since 3.2. Use {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations#batchUpdate}
|
||||
* methods instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
public class BatchJdbcOperations {
|
||||
|
||||
private final NamedParameterJdbcOperations jdbcOperations;
|
||||
|
||||
public BatchJdbcOperations(JdbcOperations jdbcOperations) {
|
||||
this.jdbcOperations = new NamedParameterJdbcTemplate(jdbcOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
|
||||
*
|
||||
* @param sql the SQL statement to execute
|
||||
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
|
||||
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
|
||||
* @return an array containing the numbers of rows affected by each update in the batch (may also contain special
|
||||
* JDBC-defined negative values for affected rows such as
|
||||
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
|
||||
* @see org.springframework.jdbc.support.GeneratedKeyHolder
|
||||
* @since 2.4
|
||||
*/
|
||||
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generatedKeyHolder) {
|
||||
return jdbcOperations.batchUpdate(sql, batchArgs, generatedKeyHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
|
||||
*
|
||||
* @param sql the SQL statement to execute
|
||||
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
|
||||
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
|
||||
* @param keyColumnNames names of the columns that will have keys generated for them
|
||||
* @return an array containing the numbers of rows affected by each update in the batch (may also contain special
|
||||
* JDBC-defined negative values for affected rows such as
|
||||
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
|
||||
* @see org.springframework.jdbc.support.GeneratedKeyHolder
|
||||
* @since 2.4
|
||||
*/
|
||||
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs, KeyHolder generatedKeyHolder,
|
||||
@Nullable String[] keyColumnNames) {
|
||||
return jdbcOperations.batchUpdate(sql, batchArgs, generatedKeyHolder, keyColumnNames);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
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.data.relational.domain.RowDocument;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -43,19 +42,6 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
private final JdbcConverter converter;
|
||||
private final @Nullable 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) {
|
||||
|
||||
|
||||
@@ -41,18 +41,6 @@ public class InsertStrategyFactory {
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with additional {@link BatchJdbcOperations} constructor.
|
||||
*
|
||||
* @deprecated since 3.2, use
|
||||
* {@link InsertStrategyFactory#InsertStrategyFactory(NamedParameterJdbcOperations, Dialect)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
public InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations,
|
||||
BatchJdbcOperations batchJdbcOperations, Dialect dialect) {
|
||||
this(namedParameterJdbcOperations, dialect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idValueSource the {@link IdValueSource} for the insert.
|
||||
* @param idColumn the identifier for the id, if an id is expected to be generated. May be {@code null}.
|
||||
|
||||
@@ -15,15 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLType;
|
||||
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcValue;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
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.domain.RowDocument;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -65,48 +61,6 @@ public interface JdbcConverter extends RelationalConverter {
|
||||
*/
|
||||
JdbcValue writeJdbcValue(@Nullable Object value, TypeInformation<?> type, SQLType sqlType);
|
||||
|
||||
/**
|
||||
* Read the current row from {@link ResultSet} to an {@link RelationalPersistentEntity#getType() entity}.
|
||||
*
|
||||
* @param entity the persistent entity type.
|
||||
* @param resultSet the {@link ResultSet} to read from.
|
||||
* @param key primary key.
|
||||
* @param <T>
|
||||
* @return
|
||||
* @deprecated since 3.2, use {@link #readAndResolve(Class, RowDocument, Identifier)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
default <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key) {
|
||||
try {
|
||||
return readAndResolve(entity.getType(), RowDocumentResultSetExtractor.toRowDocument(resultSet));
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current row from {@link ResultSet} to an {@link PersistentPropertyPathExtension#getActualType() 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
|
||||
* @deprecated use {@link #readAndResolve(Class, RowDocument, Identifier)} instead.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
default <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key) {
|
||||
|
||||
try {
|
||||
return (T) readAndResolve(path.getRequiredLeafEntity().getTypeInformation(),
|
||||
RowDocumentResultSetExtractor.toRowDocument(resultSet), identifier);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a {@link RowDocument} into the requested {@link Class aggregate type} and resolve references by looking these
|
||||
* up from {@link RelationResolver}.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
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;
|
||||
|
||||
@@ -38,17 +37,6 @@ public class JdbcIdentifierBuilder {
|
||||
return new JdbcIdentifierBuilder(Identifier.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -64,20 +52,6 @@ public class JdbcIdentifierBuilder {
|
||||
return new JdbcIdentifierBuilder(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
@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.
|
||||
*
|
||||
@@ -90,7 +64,8 @@ public class JdbcIdentifierBuilder {
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(value, "Value must not be null");
|
||||
|
||||
identifier = identifier.withPart(path.getTableInfo().qualifierColumnInfo().name(), value, path.getTableInfo().qualifierColumnType());
|
||||
identifier = identifier.withPart(path.getTableInfo().qualifierColumnInfo().name(), value,
|
||||
path.getTableInfo().qualifierColumnType());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -61,23 +61,6 @@ public class QueryMapper {
|
||||
private final JdbcConverter converter;
|
||||
private final MappingContext<? extends RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
|
||||
|
||||
/**
|
||||
* Creates a new {@link QueryMapper} with the given {@link JdbcConverter}.
|
||||
*
|
||||
* @param dialect must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @deprecated use {@link QueryMapper(JdbcConverter)} instead.
|
||||
*/
|
||||
@Deprecated(since="3.2")
|
||||
public QueryMapper(Dialect dialect, JdbcConverter converter) {
|
||||
|
||||
Assert.notNull(dialect, "Dialect must not be null");
|
||||
Assert.notNull(converter, "JdbcConverter must not be null");
|
||||
|
||||
this.converter = converter;
|
||||
this.mappingContext = converter.getMappingContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link QueryMapper} with the given {@link JdbcConverter}.
|
||||
*
|
||||
|
||||
@@ -47,15 +47,7 @@ import org.springframework.util.Assert;
|
||||
public class SqlParametersFactory {
|
||||
private final RelationalMappingContext context;
|
||||
private final JdbcConverter converter;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link SqlParametersFactory(RelationalMappingContext, JdbcConverter)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
public SqlParametersFactory(RelationalMappingContext context, JdbcConverter converter, Dialect dialect) {
|
||||
this(context, converter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 3.1
|
||||
*/
|
||||
|
||||
@@ -36,9 +36,7 @@ import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
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.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -102,8 +100,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
// the DefaultDataAccessStrategy needs a reference to the returned DataAccessStrategy. This creates a dependency
|
||||
// cycle. In order to create it, we need something that allows to defer closing the cycle until all the elements are
|
||||
// created. That is the purpose of the DelegatingAccessStrategy.
|
||||
MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession,
|
||||
dialect.getIdentifierProcessing());
|
||||
MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession);
|
||||
myBatisDataAccessStrategy.setNamespaceStrategy(namespaceStrategy);
|
||||
|
||||
return new CascadingDataAccessStrategy(
|
||||
@@ -120,15 +117,6 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
* to create such a {@link DataAccessStrategy}.
|
||||
*
|
||||
* @param sqlSession Must be non {@literal null}.
|
||||
* @deprecated because identifierProcessing now will not be considered in the process of applying it to
|
||||
* {@link SqlIdentifier}, use {@link MyBatisDataAccessStrategy(SqlSession)} constructor instead
|
||||
*/
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
public MyBatisDataAccessStrategy(SqlSession sqlSession, IdentifierProcessing identifierProcessing) {
|
||||
this(sqlSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1
|
||||
*/
|
||||
public MyBatisDataAccessStrategy(SqlSession sqlSession) {
|
||||
|
||||
@@ -72,23 +72,6 @@ public abstract class AbstractJdbcQuery implements RepositoryQuery {
|
||||
return queryMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link JdbcQueryExecution} given a {@link JdbcQueryMethod}, and ac{@link ResultSetExtractor} or a
|
||||
* {@link RowMapper}. Prefers the given {@link ResultSetExtractor} over {@link RowMapper}.
|
||||
*
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
* @param extractor must not be {@literal null}.
|
||||
* @param rowMapper must not be {@literal null}.
|
||||
* @return a JdbcQueryExecution appropriate for {@literal queryMethod}. Guaranteed to be not {@literal null}.
|
||||
* @deprecated use {@link #createReadingQueryExecution(ResultSetExtractor, RowMapper)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
// a better name would be createReadingQueryExecution
|
||||
JdbcQueryExecution<?> getQueryExecution(JdbcQueryMethod queryMethod,
|
||||
@Nullable ResultSetExtractor<?> extractor, RowMapper<?> rowMapper) {
|
||||
return createReadingQueryExecution(extractor, () -> rowMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link JdbcQueryExecution} given a {@link ResultSetExtractor} or a {@link RowMapper}. Prefers the given
|
||||
* {@link ResultSetExtractor} over {@link RowMapper}.
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2024 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
|
||||
*
|
||||
* https://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 org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.Embedded;
|
||||
import org.springframework.data.relational.core.mapping.Embedded.OnEmpty;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
/**
|
||||
* @author Jens Schauder
|
||||
* @author Daniil Razorenov
|
||||
*/
|
||||
public class PersistentPropertyPathExtensionUnitTests {
|
||||
|
||||
JdbcMappingContext context = new JdbcMappingContext();
|
||||
private RelationalPersistentEntity<?> entity = context.getRequiredPersistentEntity(DummyEntity.class);
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void isEmbedded() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).isEmbedded()).isFalse();
|
||||
softly.assertThat(extPath("second").isEmbedded()).isFalse();
|
||||
softly.assertThat(extPath("second.third2").isEmbedded()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void isMultiValued() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).isMultiValued()).isFalse();
|
||||
softly.assertThat(extPath("second").isMultiValued()).isFalse();
|
||||
softly.assertThat(extPath("second.third2").isMultiValued()).isFalse();
|
||||
softly.assertThat(extPath("secondList.third2").isMultiValued()).isTrue();
|
||||
softly.assertThat(extPath("secondList").isMultiValued()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void leafEntity() {
|
||||
|
||||
RelationalPersistentEntity<?> second = context.getRequiredPersistentEntity(Second.class);
|
||||
RelationalPersistentEntity<?> third = context.getRequiredPersistentEntity(Third.class);
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).getLeafEntity()).isEqualTo(entity);
|
||||
softly.assertThat(extPath("second").getLeafEntity()).isEqualTo(second);
|
||||
softly.assertThat(extPath("second.third2").getLeafEntity()).isEqualTo(third);
|
||||
softly.assertThat(extPath("secondList.third2").getLeafEntity()).isEqualTo(third);
|
||||
softly.assertThat(extPath("secondList").getLeafEntity()).isEqualTo(second);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void isEntity() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).isEntity()).isTrue();
|
||||
String path = "second";
|
||||
softly.assertThat(extPath(path).isEntity()).isTrue();
|
||||
softly.assertThat(extPath("second.third2").isEntity()).isTrue();
|
||||
softly.assertThat(extPath("second.third2.value").isEntity()).isFalse();
|
||||
softly.assertThat(extPath("secondList.third2").isEntity()).isTrue();
|
||||
softly.assertThat(extPath("secondList.third2.value").isEntity()).isFalse();
|
||||
softly.assertThat(extPath("secondList").isEntity()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void getTableName() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).getQualifiedTableName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("second").getQualifiedTableName()).isEqualTo(quoted("SECOND"));
|
||||
softly.assertThat(extPath("second.third2").getQualifiedTableName()).isEqualTo(quoted("SECOND"));
|
||||
softly.assertThat(extPath("second.third2.value").getQualifiedTableName()).isEqualTo(quoted("SECOND"));
|
||||
softly.assertThat(extPath("secondList.third2").getQualifiedTableName()).isEqualTo(quoted("SECOND"));
|
||||
softly.assertThat(extPath("secondList.third2.value").getQualifiedTableName()).isEqualTo(quoted("SECOND"));
|
||||
softly.assertThat(extPath("secondList").getQualifiedTableName()).isEqualTo(quoted("SECOND"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void getTableAlias() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).getTableAlias()).isEqualTo(null);
|
||||
softly.assertThat(extPath("second").getTableAlias()).isEqualTo(quoted("second"));
|
||||
softly.assertThat(extPath("second.third2").getTableAlias()).isEqualTo(quoted("second"));
|
||||
softly.assertThat(extPath("second.third2.value").getTableAlias()).isEqualTo(quoted("second"));
|
||||
softly.assertThat(extPath("second.third").getTableAlias()).isEqualTo(quoted("second_third"));
|
||||
softly.assertThat(extPath("second.third.value").getTableAlias()).isEqualTo(quoted("second_third"));
|
||||
softly.assertThat(extPath("secondList.third2").getTableAlias()).isEqualTo(quoted("secondList"));
|
||||
softly.assertThat(extPath("secondList.third2.value").getTableAlias()).isEqualTo(quoted("secondList"));
|
||||
softly.assertThat(extPath("secondList.third").getTableAlias()).isEqualTo(quoted("secondList_third"));
|
||||
softly.assertThat(extPath("secondList.third.value").getTableAlias()).isEqualTo(quoted("secondList_third"));
|
||||
softly.assertThat(extPath("secondList").getTableAlias()).isEqualTo(quoted("secondList"));
|
||||
softly.assertThat(extPath("second2.third").getTableAlias()).isEqualTo(quoted("secthird"));
|
||||
softly.assertThat(extPath("second3.third").getTableAlias()).isEqualTo(quoted("third"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
void getColumnName() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath("second.third2.value").getColumnName()).isEqualTo(quoted("THRDVALUE"));
|
||||
softly.assertThat(extPath("second.third.value").getColumnName()).isEqualTo(quoted("VALUE"));
|
||||
softly.assertThat(extPath("secondList.third2.value").getColumnName()).isEqualTo(quoted("THRDVALUE"));
|
||||
softly.assertThat(extPath("secondList.third.value").getColumnName()).isEqualTo(quoted("VALUE"));
|
||||
softly.assertThat(extPath("second2.third2.value").getColumnName()).isEqualTo(quoted("SECTHRDVALUE"));
|
||||
softly.assertThat(extPath("second2.third.value").getColumnName()).isEqualTo(quoted("VALUE"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-359
|
||||
void idDefiningPath() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath("second.third2.value").getIdDefiningParentPath().getLength()).isEqualTo(0);
|
||||
softly.assertThat(extPath("second.third.value").getIdDefiningParentPath().getLength()).isEqualTo(0);
|
||||
softly.assertThat(extPath("secondList.third2.value").getIdDefiningParentPath().getLength()).isEqualTo(0);
|
||||
softly.assertThat(extPath("secondList.third.value").getIdDefiningParentPath().getLength()).isEqualTo(0);
|
||||
softly.assertThat(extPath("second2.third2.value").getIdDefiningParentPath().getLength()).isEqualTo(0);
|
||||
softly.assertThat(extPath("second2.third.value").getIdDefiningParentPath().getLength()).isEqualTo(0);
|
||||
softly.assertThat(extPath("withId.second.third2.value").getIdDefiningParentPath().getLength()).isEqualTo(1);
|
||||
softly.assertThat(extPath("withId.second.third.value").getIdDefiningParentPath().getLength()).isEqualTo(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-359
|
||||
void reverseColumnName() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath("second.third2").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("second.third").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("secondList.third2").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("secondList.third").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("second2.third2").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("second2.third").getReverseColumnName()).isEqualTo(quoted("DUMMY_ENTITY"));
|
||||
softly.assertThat(extPath("withId.second.third2.value").getReverseColumnName()).isEqualTo(quoted("WITH_ID"));
|
||||
softly.assertThat(extPath("withId.second.third").getReverseColumnName()).isEqualTo(quoted("WITH_ID"));
|
||||
softly.assertThat(extPath("withId.second2.third").getReverseColumnName()).isEqualTo(quoted("WITH_ID"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-359
|
||||
void getRequiredIdProperty() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).getRequiredIdProperty().getName()).isEqualTo("entityId");
|
||||
softly.assertThat(extPath("withId").getRequiredIdProperty().getName()).isEqualTo("withIdId");
|
||||
softly.assertThatThrownBy(() -> extPath("second").getRequiredIdProperty())
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-359
|
||||
void extendBy() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(extPath(entity).extendBy(entity.getRequiredPersistentProperty("withId")))
|
||||
.isEqualTo(extPath("withId"));
|
||||
softly.assertThat(extPath("withId").extendBy(extPath("withId").getRequiredIdProperty()))
|
||||
.isEqualTo(extPath("withId.withIdId"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-1164
|
||||
void equalsWorks() {
|
||||
|
||||
PersistentPropertyPathExtension root1 = extPath(entity);
|
||||
PersistentPropertyPathExtension root2 = extPath(entity);
|
||||
PersistentPropertyPathExtension path1 = extPath("withId");
|
||||
PersistentPropertyPathExtension path2 = extPath("withId");
|
||||
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(root1).describedAs("root is equal to self").isEqualTo(root1);
|
||||
softly.assertThat(root2).describedAs("root is equal to identical root").isEqualTo(root1);
|
||||
softly.assertThat(path1).describedAs("path is equal to self").isEqualTo(path1);
|
||||
softly.assertThat(path2).describedAs("path is equal to identical path").isEqualTo(path1);
|
||||
softly.assertThat(path1).describedAs("path is not equal to other path").isNotEqualTo(extPath("entityId"));
|
||||
softly.assertThat(root1).describedAs("root is not equal to path").isNotEqualTo(path1);
|
||||
softly.assertThat(path1).describedAs("path is not equal to root").isNotEqualTo(root1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-1249
|
||||
void isWritable() {
|
||||
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(PersistentPropertyPathExtension.isWritable(createSimplePath("withId")))
|
||||
.describedAs("simple path is writable").isTrue();
|
||||
softly.assertThat(PersistentPropertyPathExtension.isWritable(createSimplePath("secondList.third2")))
|
||||
.describedAs("long path is writable").isTrue();
|
||||
softly.assertThat(PersistentPropertyPathExtension.isWritable(createSimplePath("second")))
|
||||
.describedAs("simple read only path is not writable").isFalse();
|
||||
softly.assertThat(PersistentPropertyPathExtension.isWritable(createSimplePath("second.third")))
|
||||
.describedAs("long path containing read only element is not writable").isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-1525
|
||||
void getAggregatePath() {
|
||||
assertThat(extPath("withId").getAggregatePath()).isNotNull();
|
||||
}
|
||||
@Test // GH-1525
|
||||
void getAggregatePathFromRoot() {
|
||||
assertThat(extPath(entity).getAggregatePath()).isNotNull();
|
||||
}
|
||||
private PersistentPropertyPathExtension extPath(RelationalPersistentEntity<?> entity) {
|
||||
return new PersistentPropertyPathExtension(context, entity);
|
||||
}
|
||||
|
||||
private PersistentPropertyPathExtension extPath(String path) {
|
||||
return new PersistentPropertyPathExtension(context, createSimplePath(path));
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> createSimplePath(String path) {
|
||||
return PersistentPropertyPathTestUtils.getPath(path, DummyEntity.class, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class DummyEntity {
|
||||
@Id Long entityId;
|
||||
@ReadOnlyProperty Second second;
|
||||
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "sec") Second second2;
|
||||
@Embedded(onEmpty = OnEmpty.USE_NULL) Second second3;
|
||||
List<Second> secondList;
|
||||
WithId withId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Second {
|
||||
Third third;
|
||||
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "thrd") Third third2;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Third {
|
||||
String value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class WithId {
|
||||
@Id Long withIdId;
|
||||
Second second;
|
||||
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "sec") Second second2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -118,8 +118,7 @@ public class MyBatisCustomizingNamespaceHsqlIntegrationTests {
|
||||
RelationalMappingContext context = new JdbcMappingContext();
|
||||
JdbcConverter converter = new MappingJdbcConverter(context, (Identifier, path) -> null);
|
||||
|
||||
MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession,
|
||||
HsqlDbDialect.INSTANCE.getIdentifierProcessing());
|
||||
MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession);
|
||||
|
||||
strategy.setNamespaceStrategy(new NamespaceStrategy() {
|
||||
@Override
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link MyBatisDataAccessStrategy}, mainly ensuring that the correct statements get's looked up.
|
||||
@@ -52,7 +51,7 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
SqlSession session = mock(SqlSession.class);
|
||||
ArgumentCaptor<MyBatisContext> captor = ArgumentCaptor.forClass(MyBatisContext.class);
|
||||
|
||||
MyBatisDataAccessStrategy accessStrategy = new MyBatisDataAccessStrategy(session, IdentifierProcessing.ANSI);
|
||||
MyBatisDataAccessStrategy accessStrategy = new MyBatisDataAccessStrategy(session);
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path = PersistentPropertyPathTestUtils.getPath("one.two",
|
||||
DummyEntity.class, context);
|
||||
|
||||
@@ -43,7 +43,6 @@ import org.springframework.data.r2dbc.dialect.DialectResolver;
|
||||
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
|
||||
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
|
||||
import org.springframework.data.relational.RelationalManagedTypes;
|
||||
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.DefaultNamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
@@ -432,15 +432,6 @@ public interface StatementMapper {
|
||||
return this.table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated since 1.1, use {@link #getSelectList()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<String> getProjectedFields() {
|
||||
return Collections.unmodifiableList(this.projectedFields);
|
||||
}
|
||||
|
||||
public List<Expression> getSelectList() {
|
||||
return Collections.unmodifiableList(selectList);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.springframework.data.r2dbc.dialect.R2dbcDialect;
|
||||
import org.springframework.data.relational.core.dialect.Escaper;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.query.Criteria;
|
||||
import org.springframework.data.relational.core.query.CriteriaDefinition;
|
||||
import org.springframework.data.relational.core.query.CriteriaDefinition.Comparator;
|
||||
import org.springframework.data.relational.core.query.ValueFunction;
|
||||
@@ -97,35 +96,6 @@ public class QueryMapper {
|
||||
return identifier.toSql(this.dialect.getIdentifierProcessing());
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the {@link Sort} object to apply field name mapping using {@link Class the type to read}.
|
||||
*
|
||||
* @param sort must not be {@literal null}.
|
||||
* @param entity related {@link RelationalPersistentEntity}, can be {@literal null}.
|
||||
* @return
|
||||
* @deprecated without replacement.
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
public Sort getMappedObject(Sort sort, @Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
if (entity == null) {
|
||||
return sort;
|
||||
}
|
||||
|
||||
List<Sort.Order> mappedOrder = new ArrayList<>();
|
||||
|
||||
for (Sort.Order order : sort) {
|
||||
|
||||
SqlSort.validate(order);
|
||||
|
||||
Field field = createPropertyField(entity, SqlIdentifier.unquoted(order.getProperty()), this.mappingContext);
|
||||
mappedOrder.add(
|
||||
Sort.Order.by(toSql(field.getMappedColumnName())).with(order.getNullHandling()).with(order.getDirection()));
|
||||
}
|
||||
|
||||
return Sort.by(mappedOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the {@link Sort} object to apply field name mapping using {@link Class the type to read}.
|
||||
*
|
||||
@@ -229,35 +199,6 @@ public class QueryMapper {
|
||||
return new BoundCondition(bindings, mapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a {@link Criteria} object into {@link Condition} and consider value/{@code NULL} {@link Bindings}.
|
||||
*
|
||||
* @param markers bind markers object, must not be {@literal null}.
|
||||
* @param criteria criteria definition to map, must not be {@literal null}.
|
||||
* @param table must not be {@literal null}.
|
||||
* @param entity related {@link RelationalPersistentEntity}, can be {@literal null}.
|
||||
* @return the mapped {@link BoundCondition}.
|
||||
* @deprecated since 1.1.
|
||||
*/
|
||||
@Deprecated
|
||||
public BoundCondition getMappedObject(BindMarkers markers, Criteria criteria, Table table,
|
||||
@Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(markers, "BindMarkers must not be null");
|
||||
Assert.notNull(criteria, "Criteria must not be null");
|
||||
Assert.notNull(table, "Table must not be null");
|
||||
|
||||
MutableBindings bindings = new MutableBindings(markers);
|
||||
|
||||
if (criteria.isEmpty()) {
|
||||
throw new IllegalArgumentException("Cannot map empty Criteria");
|
||||
}
|
||||
|
||||
Condition mapped = unroll(criteria, table, entity, bindings);
|
||||
|
||||
return new BoundCondition(bindings, mapped);
|
||||
}
|
||||
|
||||
private Condition unroll(CriteriaDefinition criteria, Table table, @Nullable RelationalPersistentEntity<?> entity,
|
||||
MutableBindings bindings) {
|
||||
|
||||
|
||||
@@ -427,26 +427,6 @@ class QueryMapperUnitTests {
|
||||
assertThat(bindings.getCondition()).hasToString("person.name LIKE ?[$1]");
|
||||
}
|
||||
|
||||
@Test // gh-64
|
||||
void shouldMapSort() {
|
||||
|
||||
Sort sort = Sort.by(desc("alternative"));
|
||||
|
||||
Sort mapped = mapper.getMappedObject(sort, mapper.getMappingContext().getRequiredPersistentEntity(Person.class));
|
||||
|
||||
assertThat(mapped.getOrderFor("another_name")).isEqualTo(desc("another_name"));
|
||||
assertThat(mapped.getOrderFor("alternative")).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-369
|
||||
void mapSortForPropertyPathInPrimitiveShouldFallBackToColumnName() {
|
||||
|
||||
Sort sort = Sort.by(desc("alternative_name"));
|
||||
|
||||
Sort mapped = mapper.getMappedObject(sort, mapper.getMappingContext().getRequiredPersistentEntity(Person.class));
|
||||
assertThat(mapped.getOrderFor("alternative_name")).isEqualTo(desc("alternative_name"));
|
||||
}
|
||||
|
||||
@Test // GH-1507
|
||||
public void shouldMapSortWithUnknownField() {
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2024 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.relational.core.conversion;
|
||||
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
* {@link RelationalConverter} that uses a {@link MappingContext} to apply basic conversion of relational values to
|
||||
* property values.
|
||||
* <p>
|
||||
* Conversion is configurable by providing a customized {@link CustomConversions}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Chirag Tailor
|
||||
* @author Vincent Galloy
|
||||
* @see MappingContext
|
||||
* @see SimpleTypeHolder
|
||||
* @see CustomConversions
|
||||
* @deprecated since 3.2, use {@link MappingRelationalConverter} instead as the naming suggests a limited scope of
|
||||
* functionality.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
public class BasicRelationalConverter extends MappingRelationalConverter {
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public BasicRelationalConverter(RelationalMappingContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and {@link CustomConversions}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param conversions must not be {@literal null}.
|
||||
*/
|
||||
public BasicRelationalConverter(RelationalMappingContext context, CustomConversions conversions) {
|
||||
super(context, conversions);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -472,14 +472,6 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
|
||||
return populateProperties(context, entity, documentAccessor, evaluator, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T createInstance(PersistentEntity<T, RelationalPersistentProperty> entity,
|
||||
Function<Parameter<?, RelationalPersistentProperty>, Object> parameterValueProvider) {
|
||||
|
||||
return getEntityInstantiators().getInstantiatorFor(entity) //
|
||||
.createInstance(entity, new ConvertingParameterValueProvider<>(parameterValueProvider));
|
||||
}
|
||||
|
||||
private ParameterValueProvider<RelationalPersistentProperty> getParameterProvider(ConversionContext context,
|
||||
RelationalPersistentEntity<?> entity, RowDocumentAccessor source, ValueExpressionEvaluator evaluator) {
|
||||
|
||||
|
||||
@@ -63,23 +63,6 @@ public interface RelationalConverter {
|
||||
*/
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> getMappingContext();
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link PersistentEntity} given {@link ParameterValueProvider} to obtain constructor
|
||||
* properties.
|
||||
*
|
||||
* @param entity the kind of entity to create. Must not be {@code null}.
|
||||
* @param parameterValueProvider a function that provides the value to pass to a constructor, given a
|
||||
* {@link Parameter}. Must not be {@code null}.
|
||||
* @param <T> the type of entity to create.
|
||||
* @return the instantiated entity. Guaranteed to be not {@code null}.
|
||||
* @deprecated since 3.2, use {@link #read} method instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2")
|
||||
default <T> T createInstance(PersistentEntity<T, RelationalPersistentProperty> entity,
|
||||
Function<Parameter<?, RelationalPersistentProperty>, Object> parameterValueProvider) {
|
||||
throw new UnsupportedOperationException("Not supported anymore. Use read(…) instead.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link PersistentPropertyAccessor} to access property values of the {@code instance}.
|
||||
*
|
||||
|
||||
@@ -22,8 +22,6 @@ import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.data.convert.EntityWriter;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
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.RelationalPersistentProperty;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -24,8 +24,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
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;
|
||||
|
||||
@@ -63,22 +63,6 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
|
||||
private boolean forceQuote = true;
|
||||
private ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator(EvaluationContextProvider.DEFAULT);
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalPersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param owner must not be {@literal null}.
|
||||
* @param simpleTypeHolder must not be {@literal null}.
|
||||
* @param context must not be {@literal null}
|
||||
* @since 2.0, use
|
||||
* {@link #BasicRelationalPersistentProperty(Property, PersistentEntity, SimpleTypeHolder, NamingStrategy)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public BasicRelationalPersistentProperty(Property property, PersistentEntity<?, RelationalPersistentProperty> owner,
|
||||
SimpleTypeHolder simpleTypeHolder, RelationalMappingContext context) {
|
||||
this(property, owner, simpleTypeHolder, context.getNamingStrategy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalPersistentProperty}.
|
||||
*
|
||||
@@ -222,18 +206,6 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent
|
||||
return (RelationalPersistentEntity<?>) super.getOwner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) {
|
||||
|
||||
if (collectionIdColumnNameExpression == null) {
|
||||
|
||||
return collectionIdColumnName.get()
|
||||
.orElseGet(() -> createDerivedSqlIdentifier(this.namingStrategy.getReverseColumnName(path)));
|
||||
}
|
||||
|
||||
return createSqlIdentifier(expressionEvaluator.evaluate(collectionIdColumnNameExpression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlIdentifier getReverseColumnName(RelationalPersistentEntity<?> owner) {
|
||||
|
||||
|
||||
@@ -62,11 +62,6 @@ class CachingNamingStrategy implements NamingStrategy {
|
||||
return tableNames.computeIfAbsent(type, delegate::getTableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReverseColumnName(PersistentPropertyPathExtension path) {
|
||||
return delegate.getReverseColumnName(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReverseColumnName(RelationalPersistentProperty property) {
|
||||
return delegate.getReverseColumnName(property);
|
||||
|
||||
@@ -52,15 +52,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
|
||||
return getColumnNameReferencing(property.getOwner());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReverseColumnName(PersistentPropertyPathExtension path) {
|
||||
|
||||
RelationalPersistentEntity<?> leafEntity = path.getIdDefiningParentPath().getRequiredLeafEntity();
|
||||
|
||||
return getColumnNameReferencing(leafEntity);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getReverseColumnName(RelationalPersistentEntity<?> parent) {
|
||||
return getColumnNameReferencing(parent);
|
||||
|
||||
@@ -75,12 +75,6 @@ class DerivedSqlIdentifier implements SqlIdentifier {
|
||||
return sqlName.sqlName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
public String getReference(IdentifierProcessing processing) {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
|
||||
@@ -69,12 +69,6 @@ class EmbeddedRelationalPersistentProperty implements RelationalPersistentProper
|
||||
return delegate.getOwner();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
public SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path) {
|
||||
return delegate.getReverseColumnName(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlIdentifier getReverseColumnName(RelationalPersistentEntity<?> owner) {
|
||||
return delegate.getReverseColumnName(owner);
|
||||
|
||||
@@ -34,15 +34,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public interface NamingStrategy {
|
||||
|
||||
/**
|
||||
* Empty implementation of the interface utilizing only the default implementation.
|
||||
* <p>
|
||||
* Using this avoids creating essentially the same class over and over again.
|
||||
*
|
||||
* @deprecated use {@link DefaultNamingStrategy#INSTANCE} instead.
|
||||
*/
|
||||
@Deprecated(since = "2.4", forRemoval = true) NamingStrategy INSTANCE = DefaultNamingStrategy.INSTANCE;
|
||||
|
||||
/**
|
||||
* Defaults to no schema.
|
||||
*
|
||||
@@ -87,14 +78,6 @@ public interface NamingStrategy {
|
||||
return property.getOwner().getTableName().getReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getReverseColumnName(RelationalPersistentEntity)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
default String getReverseColumnName(PersistentPropertyPathExtension path) {
|
||||
return getReverseColumnName(path.getRequiredLeafEntity());
|
||||
}
|
||||
|
||||
default String getReverseColumnName(RelationalPersistentEntity<?> owner) {
|
||||
return getTableName(owner.getType());
|
||||
}
|
||||
|
||||
@@ -1,485 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2024 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.relational.core.mapping;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A wrapper around a {@link org.springframework.data.mapping.PersistentPropertyPath} for making common operations
|
||||
* available used in SQL generation and conversion
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Daniil Razorenov
|
||||
* @author Kurt Niemi
|
||||
* @since 1.1
|
||||
* @deprecated use {@link AggregatePath} instead
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
public class PersistentPropertyPathExtension {
|
||||
|
||||
private final RelationalPersistentEntity<?> entity;
|
||||
private final @Nullable PersistentPropertyPath<? extends RelationalPersistentProperty> path;
|
||||
private final MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context;
|
||||
|
||||
private final Lazy<SqlIdentifier> columnAlias = Lazy.of(() -> prefixWithTableAlias(getColumnName()));
|
||||
|
||||
/**
|
||||
* Creates the empty path referencing the root itself.
|
||||
*
|
||||
* @param context Must not be {@literal null}.
|
||||
* @param entity Root entity of the path. Must not be {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyPathExtension(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
RelationalPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(context, "Context must not be null");
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
|
||||
this.context = context;
|
||||
this.entity = entity;
|
||||
this.path = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a non-empty path.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param path must not be {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyPathExtension(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> path) {
|
||||
|
||||
Assert.notNull(context, "Context must not be null");
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(path.getBaseProperty(), "Path must not be empty.");
|
||||
|
||||
this.context = context;
|
||||
this.entity = path.getBaseProperty().getOwner();
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public static boolean isWritable(@Nullable PersistentPropertyPath<? extends RelationalPersistentProperty> path) {
|
||||
return path == null || path.getLeafProperty().isWritable() && isWritable(path.getParentPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@literal true} exactly when the path is non-empty and the leaf property an embedded one.
|
||||
*
|
||||
* @return if the leaf property is embedded.
|
||||
*/
|
||||
public boolean isEmbedded() {
|
||||
return path != null && path.getLeafProperty().isEmbedded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path that has the same beginning but is one segment shorter than this path.
|
||||
*
|
||||
* @return the parent path. Guaranteed to be not {@literal null}.
|
||||
* @throws IllegalStateException when called on an empty path.
|
||||
*/
|
||||
public PersistentPropertyPathExtension getParentPath() {
|
||||
|
||||
if (path == null) {
|
||||
throw new IllegalStateException("The parent path of a root path is not defined.");
|
||||
}
|
||||
|
||||
if (path.getLength() == 1) {
|
||||
return new PersistentPropertyPathExtension(context, entity);
|
||||
}
|
||||
|
||||
return new PersistentPropertyPathExtension(context, path.getParentPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@literal true} if there are multiple values for this path, i.e. if the path contains at least one element
|
||||
* that is a collection and array or a map.
|
||||
*
|
||||
* @return {@literal true} if the path contains a multivalued element.
|
||||
*/
|
||||
public boolean isMultiValued() {
|
||||
|
||||
return path != null && //
|
||||
(path.getLeafProperty().isCollectionLike() //
|
||||
|| path.getLeafProperty().isQualified() //
|
||||
|| getParentPath().isMultiValued() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link RelationalPersistentEntity} associated with the leaf of this path.
|
||||
*
|
||||
* @return Might return {@literal null} when called on a path that does not represent an entity.
|
||||
*/
|
||||
@Nullable
|
||||
public RelationalPersistentEntity<?> getLeafEntity() {
|
||||
return path == null ? entity
|
||||
: context.getPersistentEntity(path.getLeafProperty().getTypeInformation().getActualType());
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link RelationalPersistentEntity} associated with the leaf of this path or throw {@link IllegalStateException}
|
||||
* if the leaf cannot be resolved.
|
||||
*
|
||||
* @return the required {@link RelationalPersistentEntity} associated with the leaf of this path.
|
||||
* @since 3.0
|
||||
* @throws IllegalStateException if the persistent entity cannot be resolved.
|
||||
*/
|
||||
public RelationalPersistentEntity<?> getRequiredLeafEntity() {
|
||||
|
||||
RelationalPersistentEntity<?> entity = getLeafEntity();
|
||||
|
||||
if (entity == null) {
|
||||
|
||||
if (this.path == null) {
|
||||
throw new IllegalStateException("Couldn't resolve leaf PersistentEntity absent path");
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
String.format("Couldn't resolve leaf PersistentEntity for type %s", path.getLeafProperty().getActualType()));
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} when this is an empty path or the path references an entity.
|
||||
*/
|
||||
public boolean isEntity() {
|
||||
return path == null || path.getLeafProperty().isEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} when this is references a {@link java.util.List} or {@link java.util.Map}.
|
||||
*/
|
||||
public boolean isQualified() {
|
||||
return path != null && path.getLeafProperty().isQualified();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} when this is references a {@link java.util.Collection} or an array.
|
||||
*/
|
||||
public boolean isCollectionLike() {
|
||||
return path != null && path.getLeafProperty().isCollectionLike();
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the column used to reference the id in the parent table.
|
||||
*
|
||||
* @throws IllegalStateException when called on an empty path.
|
||||
*/
|
||||
public SqlIdentifier getReverseColumnName() {
|
||||
|
||||
Assert.state(path != null, "Empty paths don't have a reverse column name");
|
||||
return path.getLeafProperty().getReverseColumnName(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The alias used in select for the column used to reference the id in the parent table.
|
||||
*
|
||||
* @throws IllegalStateException when called on an empty path.
|
||||
*/
|
||||
public SqlIdentifier getReverseColumnNameAlias() {
|
||||
|
||||
return prefixWithTableAlias(getReverseColumnName());
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the column used to represent this property in the database.
|
||||
*
|
||||
* @throws IllegalStateException when called on an empty path.
|
||||
*/
|
||||
public SqlIdentifier getColumnName() {
|
||||
|
||||
Assert.state(path != null, "Path is null");
|
||||
|
||||
return path.getLeafProperty().getColumnName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The alias for the column used to represent this property in the database.
|
||||
*
|
||||
* @throws IllegalStateException when called on an empty path.
|
||||
*/
|
||||
public SqlIdentifier getColumnAlias() {
|
||||
return columnAlias.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this path represents an entity which has an Id attribute.
|
||||
*/
|
||||
public boolean hasIdProperty() {
|
||||
|
||||
RelationalPersistentEntity<?> leafEntity = getLeafEntity();
|
||||
return leafEntity != null && leafEntity.hasIdProperty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the longest ancestor path that has an {@link org.springframework.data.annotation.Id} property.
|
||||
*
|
||||
* @return A path that starts just as this path but is shorter. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyPathExtension getIdDefiningParentPath() {
|
||||
|
||||
PersistentPropertyPathExtension parent = getParentPath();
|
||||
|
||||
if (parent.path == null) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
if (!parent.hasIdProperty()) {
|
||||
return parent.getIdDefiningParentPath();
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The fully qualified name of the table this path is tied to or of the longest ancestor path that is actually tied to
|
||||
* a table.
|
||||
*
|
||||
* @return the name of the table. Guaranteed to be not {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public SqlIdentifier getQualifiedTableName() {
|
||||
return getTableOwningAncestor().getRequiredLeafEntity().getQualifiedTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the table this path is tied to or of the longest ancestor path that is actually tied to a table.
|
||||
*
|
||||
* @return the name of the table. Guaranteed to be not {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public SqlIdentifier getTableName() {
|
||||
return getTableOwningAncestor().getRequiredLeafEntity().getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The alias used for the table on which this path is based.
|
||||
*
|
||||
* @return a table alias, {@literal null} if the table owning path is the empty path.
|
||||
*/
|
||||
@Nullable
|
||||
public SqlIdentifier getTableAlias() {
|
||||
|
||||
PersistentPropertyPathExtension tableOwner = getTableOwningAncestor();
|
||||
|
||||
return tableOwner.path == null ? null : tableOwner.assembleTableAlias();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The column name of the id column of the ancestor path that represents an actual table.
|
||||
*/
|
||||
public SqlIdentifier getIdColumnName() {
|
||||
return getTableOwningAncestor().getRequiredLeafEntity().getIdColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the table owning ancestor has an id the column name of that id property is returned. Otherwise the reverse
|
||||
* column is returned.
|
||||
*/
|
||||
public SqlIdentifier getEffectiveIdColumnName() {
|
||||
|
||||
PersistentPropertyPathExtension owner = getTableOwningAncestor();
|
||||
return owner.path == null ? owner.getRequiredLeafEntity().getIdColumn() : owner.getReverseColumnName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The length of the path.
|
||||
*/
|
||||
public int getLength() {
|
||||
return path == null ? 0 : path.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if {@code this} and the argument represent the same path.
|
||||
*
|
||||
* @param path to which this path gets compared. May be {@literal null}.
|
||||
* @return Whence the argument matches the path represented by this instance.
|
||||
*/
|
||||
public boolean matches(PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
return this.path == null ? path.isEmpty() : this.path.equals(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* The id property of the final element of the path.
|
||||
*
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
* @throws IllegalStateException if no such property exists.
|
||||
*/
|
||||
public RelationalPersistentProperty getRequiredIdProperty() {
|
||||
return this.path == null ? entity.getRequiredIdProperty() : getRequiredLeafEntity().getRequiredIdProperty();
|
||||
}
|
||||
|
||||
/**
|
||||
* The column name used for the list index or map key of the leaf property of this path.
|
||||
*
|
||||
* @return May be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
public SqlIdentifier getQualifierColumn() {
|
||||
return path == null ? SqlIdentifier.EMPTY : path.getLeafProperty().getKeyColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the qualifier column of the leaf property of this path or {@literal null} if this is not applicable.
|
||||
*
|
||||
* @return may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
public Class<?> getQualifierColumnType() {
|
||||
return path == null ? null : path.getLeafProperty().getQualifierColumnType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new path by extending the current path by the property passed as an argument.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyPathExtension extendBy(RelationalPersistentProperty property) {
|
||||
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> newPath = path == null //
|
||||
? context.getPersistentPropertyPath(property.getName(), entity.getTypeInformation()) //
|
||||
: context.getPersistentPropertyPath(path.toDotPath() + "." + property.getName(), entity.getTypeInformation());
|
||||
|
||||
return new PersistentPropertyPathExtension(context, newPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PersistentPropertyPathExtension[%s, %s]", entity.getName(),
|
||||
path == null ? "-" : path.toDotPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* For empty paths this is the type of the entity. For non empty paths this is the actual type of the leaf property.
|
||||
*
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
* @see PersistentProperty#getActualType()
|
||||
*/
|
||||
public Class<?> getActualType() {
|
||||
|
||||
return path == null //
|
||||
? entity.getType() //
|
||||
: path.getLeafProperty().getActualType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if the leaf property of this path is a {@link java.util.Map}.
|
||||
* @see RelationalPersistentProperty#isMap()
|
||||
*/
|
||||
public boolean isMap() {
|
||||
return path != null && path.getLeafProperty().isMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this path to a non-null {@link PersistentPropertyPath}.
|
||||
*
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
* @throws IllegalStateException if this path is empty.
|
||||
*/
|
||||
public PersistentPropertyPath<? extends RelationalPersistentProperty> getRequiredPersistentPropertyPath() {
|
||||
|
||||
Assert.state(path != null, "No path.");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns the longest path with ich identical or an ancestor to the current path and maps directly to a
|
||||
* table.
|
||||
*
|
||||
* @return a path. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
private PersistentPropertyPathExtension getTableOwningAncestor() {
|
||||
|
||||
return isEntity() && !isEmbedded() ? this : getParentPath().getTableOwningAncestor();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SqlIdentifier assembleTableAlias() {
|
||||
|
||||
Assert.state(path != null, "Path is null");
|
||||
|
||||
RelationalPersistentProperty leafProperty = path.getLeafProperty();
|
||||
String prefix;
|
||||
if (isEmbedded()) {
|
||||
prefix = leafProperty.getEmbeddedPrefix();
|
||||
|
||||
} else {
|
||||
prefix = leafProperty.getName();
|
||||
}
|
||||
|
||||
if (path.getLength() == 1) {
|
||||
Assert.notNull(prefix, "Prefix mus not be null");
|
||||
return StringUtils.hasText(prefix) ? SqlIdentifier.quoted(prefix) : null;
|
||||
}
|
||||
|
||||
PersistentPropertyPathExtension parentPath = getParentPath();
|
||||
SqlIdentifier sqlIdentifier = parentPath.assembleTableAlias();
|
||||
|
||||
if (sqlIdentifier != null) {
|
||||
|
||||
return parentPath.isEmbedded() ? sqlIdentifier.transform(name -> name.concat(prefix))
|
||||
: sqlIdentifier.transform(name -> name + "_" + prefix);
|
||||
}
|
||||
return SqlIdentifier.quoted(prefix);
|
||||
|
||||
}
|
||||
|
||||
private SqlIdentifier prefixWithTableAlias(SqlIdentifier columnName) {
|
||||
|
||||
SqlIdentifier tableAlias = getTableAlias();
|
||||
return tableAlias == null ? columnName : columnName.transform(name -> tableAlias.getReference() + "_" + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
PersistentPropertyPathExtension that = (PersistentPropertyPathExtension) o;
|
||||
return entity.equals(that.entity) && Objects.equals(path, that.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(entity, path);
|
||||
}
|
||||
|
||||
public AggregatePath getAggregatePath() {
|
||||
if (path != null) {
|
||||
|
||||
return ((RelationalMappingContext) context).getAggregatePath(path);
|
||||
} else {
|
||||
return ((RelationalMappingContext) context).getAggregatePath(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,12 +46,6 @@ public interface RelationalPersistentProperty extends PersistentProperty<Relatio
|
||||
@Override
|
||||
RelationalPersistentEntity<?> getOwner();
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getReverseColumnName(RelationalPersistentEntity)} instead
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
SqlIdentifier getReverseColumnName(PersistentPropertyPathExtension path);
|
||||
|
||||
/**
|
||||
* @param owner the owning entity.
|
||||
* @return the column name to represent the owning side.
|
||||
|
||||
@@ -65,12 +65,6 @@ class CompositeSqlIdentifier implements SqlIdentifier {
|
||||
return stringJoiner.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(since="3.1", forRemoval = true)
|
||||
public String getReference(IdentifierProcessing processing) {
|
||||
throw new UnsupportedOperationException("Composite SQL Identifiers can't be used for reference name retrieval");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
|
||||
@@ -73,12 +73,6 @@ class DefaultSqlIdentifier implements SqlIdentifier {
|
||||
return sqlName.sqlName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
public String getReference(IdentifierProcessing processing) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
|
||||
@@ -63,27 +63,11 @@ public interface SqlIdentifier extends Streamable<SqlIdentifier> {
|
||||
throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create SQL snippets");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReference(IdentifierProcessing processing) {
|
||||
throw new UnsupportedOperationException("An empty SqlIdentifier can't be used in to create column names");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "<NULL-IDENTIFIER>";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the reference name after applying {@link IdentifierProcessing} rules. The reference name is used for
|
||||
* programmatic access to the object identified by this {@link SqlIdentifier}.
|
||||
*
|
||||
* @param processing identifier processing rules.
|
||||
* @return
|
||||
* @deprecated since 3.1, use the #getReference() method instead.
|
||||
*/
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
String getReference(IdentifierProcessing processing);
|
||||
|
||||
/**
|
||||
* The reference name is used for programmatic access to the object identified by this {@link SqlIdentifier}. Use this
|
||||
* method whenever accessing a column in a ResultSet and we do not want any quoting applied.
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2024 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.relational.core.conversion;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.convert.ConverterBuilder;
|
||||
import org.springframework.data.convert.ConverterBuilder.ConverterAware;
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BasicRelationalConverter}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
class BasicRelationalConverterUnitTests {
|
||||
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
RelationalConverter converter;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception {
|
||||
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.addAll(
|
||||
ConverterBuilder.writing(MyValue.class, String.class, MyValue::foo).andReading(MyValue::new).getConverters());
|
||||
|
||||
ConverterAware converterAware = ConverterBuilder
|
||||
.writing(MySimpleEnum.class, MySimpleEnum.class, Function.identity()).andReading(mySimpleEnum -> mySimpleEnum);
|
||||
converters.addAll(converterAware.getConverters());
|
||||
|
||||
CustomConversions conversions = new CustomConversions(CustomConversions.StoreConversions.NONE, converters);
|
||||
context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
|
||||
|
||||
converter = new BasicRelationalConverter(context, conversions);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-235
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldUseConvertingPropertyAccessor() {
|
||||
|
||||
RelationalPersistentEntity<MyEntity> entity = (RelationalPersistentEntity) context
|
||||
.getRequiredPersistentEntity(MyEntity.class);
|
||||
|
||||
MyEntity instance = new MyEntity();
|
||||
|
||||
PersistentPropertyAccessor<MyEntity> accessor = converter.getPropertyAccessor(entity, instance);
|
||||
RelationalPersistentProperty property = entity.getRequiredPersistentProperty("flag");
|
||||
accessor.setProperty(property, "1");
|
||||
|
||||
assertThat(instance.flag).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-235
|
||||
void shouldConvertEnumToString() {
|
||||
|
||||
Object result = converter.writeValue(MyEnum.ON, TypeInformation.of(String.class));
|
||||
|
||||
assertThat(result).isEqualTo("ON");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConvertEnumArrayToStringArray() {
|
||||
|
||||
Object result = converter.writeValue(new MyEnum[] { MyEnum.ON }, TypeInformation.OBJECT);
|
||||
|
||||
assertThat(result).isEqualTo(new String[] { "ON" });
|
||||
}
|
||||
|
||||
@Test // GH-1593
|
||||
void shouldRetainEnumArray() {
|
||||
|
||||
Object result = converter.writeValue(new MySimpleEnum[] { MySimpleEnum.ON }, TypeInformation.OBJECT);
|
||||
|
||||
assertThat(result).isEqualTo(new MySimpleEnum[] { MySimpleEnum.ON });
|
||||
}
|
||||
|
||||
@Test // GH-1593
|
||||
void shouldConvertStringToEnum() {
|
||||
|
||||
Object result = converter.readValue("OFF", TypeInformation.of(MyEnum.class));
|
||||
|
||||
assertThat(result).isEqualTo(MyEnum.OFF);
|
||||
}
|
||||
|
||||
@Test // GH-1046
|
||||
void shouldConvertArrayElementsToTargetElementType() throws NoSuchMethodException {
|
||||
|
||||
TypeInformation<?> typeInformation = TypeInformation.fromReturnTypeOf(EntityWithArray.class.getMethod("floats"));
|
||||
Double[] value = { 1.2d, 1.3d, 1.4d };
|
||||
Object result = converter.readValue(value, typeInformation);
|
||||
assertThat(result).isEqualTo(Arrays.asList(1.2f, 1.3f, 1.4f));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-235
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldCreateInstance() {
|
||||
|
||||
RelationalPersistentEntity<WithConstructorCreation> entity = (RelationalPersistentEntity) context
|
||||
.getRequiredPersistentEntity(WithConstructorCreation.class);
|
||||
|
||||
WithConstructorCreation result = converter.createInstance(entity, it -> "bar");
|
||||
|
||||
assertThat(result.foo).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-516
|
||||
void shouldConsiderWriteConverter() {
|
||||
|
||||
Object result = converter.writeValue(new MyValue("hello-world"), TypeInformation.of(String.class));
|
||||
|
||||
assertThat(result).isEqualTo("hello-world");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-516
|
||||
void shouldConsiderReadConverter() {
|
||||
|
||||
Object result = converter.readValue("hello-world", TypeInformation.of(MyValue.class));
|
||||
|
||||
assertThat(result).isEqualTo(new MyValue("hello-world"));
|
||||
}
|
||||
|
||||
record EntityWithArray(List<Float> floats) {
|
||||
}
|
||||
|
||||
static class MyEntity {
|
||||
boolean flag;
|
||||
}
|
||||
|
||||
record WithConstructorCreation(String foo) {
|
||||
}
|
||||
|
||||
record MyValue(String foo) {
|
||||
}
|
||||
|
||||
static class MyEntityWithConvertibleProperty {
|
||||
|
||||
MyValue myValue;
|
||||
}
|
||||
|
||||
enum MyEnum {
|
||||
ON, OFF;
|
||||
}
|
||||
|
||||
enum MySimpleEnum {
|
||||
ON, OFF;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,6 @@ public class DerivedSqlIdentifierUnitTests {
|
||||
SqlIdentifier identifier = new DerivedSqlIdentifier("someName", true);
|
||||
|
||||
assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[somename]");
|
||||
assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName");
|
||||
assertThat(identifier.getReference()).isEqualTo("someName");
|
||||
}
|
||||
|
||||
@@ -52,7 +51,6 @@ public class DerivedSqlIdentifierUnitTests {
|
||||
String sql = identifier.toSql(BRACKETS_LOWER_CASE);
|
||||
|
||||
assertThat(sql).isEqualTo("somename");
|
||||
assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName");
|
||||
assertThat(identifier.getReference()).isEqualTo("someName");
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ public class SqlIdentifierUnitTests {
|
||||
SqlIdentifier identifier = quoted("someName");
|
||||
|
||||
assertThat(identifier.toSql(BRACKETS_LOWER_CASE)).isEqualTo("[someName]");
|
||||
assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName");
|
||||
assertThat(identifier.getReference()).isEqualTo("someName");
|
||||
}
|
||||
|
||||
@@ -52,7 +51,6 @@ public class SqlIdentifierUnitTests {
|
||||
String sql = identifier.toSql(BRACKETS_LOWER_CASE);
|
||||
|
||||
assertThat(sql).isEqualTo("someName");
|
||||
assertThat(identifier.getReference(BRACKETS_LOWER_CASE)).isEqualTo("someName");
|
||||
assertThat(identifier.getReference()).isEqualTo("someName");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
[[mapping]]
|
||||
= Mapping
|
||||
|
||||
Rich mapping support is provided by the `BasicJdbcConverter`. `BasicJdbcConverter` has a rich metadata model that allows mapping domain objects to a data row.
|
||||
Rich mapping support is provided by the `MappingJdbcConverter`. `MappingJdbcConverter` has a rich metadata model that allows mapping domain objects to a data row.
|
||||
The mapping metadata model is populated by using annotations on your domain objects.
|
||||
However, the infrastructure is not limited to using annotations as the only source of metadata information.
|
||||
The `BasicJdbcConverter` also lets you map objects to rows without providing any additional metadata, by following a set of conventions.
|
||||
The `MappingJdbcConverter` also lets you map objects to rows without providing any additional metadata, by following a set of conventions.
|
||||
|
||||
This section describes the features of the `BasicJdbcConverter`, including how to use conventions for mapping objects to rows and how to override those conventions with annotation-based mapping metadata.
|
||||
This section describes the features of the `MappingJdbcConverter`, including how to use conventions for mapping objects to rows and how to override those conventions with annotation-based mapping metadata.
|
||||
|
||||
Read on the basics about xref:object-mapping.adoc[] before continuing with this chapter.
|
||||
|
||||
[[mapping.conventions]]
|
||||
== Convention-based Mapping
|
||||
|
||||
`BasicJdbcConverter` has a few conventions for mapping objects to rows when no additional mapping metadata is provided.
|
||||
`MappingJdbcConverter` has a few conventions for mapping objects to rows when no additional mapping metadata is provided.
|
||||
The conventions are:
|
||||
|
||||
* The short Java class name is mapped to the table name in the following manner.
|
||||
|
||||
Reference in New Issue
Block a user