Polishing.

Do not expose setForeignKeyNaming methods on NamingStrategy to make less assumptions about how a naming strategy gets implemented. Provide getRequiredLeafEntity method on PersistentPropertyPathExtension to reduce null and state assertion checks.

Refine getTableName/getQualifiedTableName approach to reduce API surface and avoid deprecations.

See #1147
Original pull request: #1324.
This commit is contained in:
Mark Paluch
2022-10-05 11:26:46 +02:00
parent e7d32bbea2
commit 795e244511
19 changed files with 163 additions and 182 deletions

View File

@@ -25,6 +25,7 @@ import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.ConverterNotFoundException;
@@ -498,9 +499,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
private boolean hasInstanceValues(@Nullable Object idValue) {
RelationalPersistentEntity<?> persistentEntity = path.getLeafEntity();
Assert.state(persistentEntity != null, "Entity must not be null");
RelationalPersistentEntity<?> persistentEntity = path.getRequiredLeafEntity();
for (RelationalPersistentProperty embeddedProperty : persistentEntity) {

View File

@@ -37,7 +37,7 @@ class SqlContext {
SqlContext(RelationalPersistentEntity<?> entity) {
this.entity = entity;
this.table = Table.create(entity.getFullTableName());
this.table = Table.create(entity.getQualifiedTableName());
}
Column getIdColumn() {
@@ -55,7 +55,7 @@ class SqlContext {
Table getTable(PersistentPropertyPathExtension path) {
SqlIdentifier tableAlias = path.getTableAlias();
Table table = Table.create(path.getTableName());
Table table = Table.create(path.getQualifiedTableName());
return tableAlias == null ? table : table.as(tableAlias);
}

View File

@@ -133,7 +133,7 @@ class SqlGenerator {
return rootCondition.apply(filterColumn);
}
Table subSelectTable = Table.create(parentPath.getTableName());
Table subSelectTable = Table.create(parentPath.getQualifiedTableName());
Column idColumn = subSelectTable.column(parentPath.getIdColumnName());
Column selectFilterColumn = subSelectTable.column(parentPath.getEffectiveIdColumnName());
@@ -208,6 +208,7 @@ class SqlGenerator {
* @param parentIdentifier name of the column of the FK back to the referencing entity.
* @param propertyPath used to determine if the property is ordered and if there is a key column.
* @return a SQL String.
* @since 3.0
*/
String getFindAllByProperty(Identifier parentIdentifier,
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath) {
@@ -706,7 +707,7 @@ class SqlGenerator {
private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path,
Function<Column, Condition> rootCondition) {
Table table = Table.create(path.getTableName());
Table table = Table.create(path.getQualifiedTableName());
DeleteBuilder.DeleteWhere builder = Delete.builder() //
.from(table);
@@ -935,7 +936,7 @@ class SqlGenerator {
private SelectBuilder.SelectOrdered applyQueryOnSelect(Query query, MapSqlParameterSource parameterSource,
SelectBuilder.SelectWhere selectBuilder) {
Table table = Table.create(this.entity.getFullTableName());
Table table = Table.create(this.entity.getQualifiedTableName());
SelectBuilder.SelectOrdered selectOrdered = query //
.getCriteria() //
@@ -1098,8 +1099,7 @@ class SqlGenerator {
if (!property.isWritable()) {
readOnlyColumnNames.add(columnName);
}
if (property.isInsertOnly()) {
if (property.isInsertOnly()) {
insertOnlyColumnNames.add(columnName);
}
}

View File

@@ -38,7 +38,7 @@ class SqlContext {
SqlContext(RelationalPersistentEntity<?> entity) {
this.entity = entity;
this.table = Table.create(entity.getFullTableName());
this.table = Table.create(entity.getQualifiedTableName());
}
Column getIdColumn() {
@@ -56,7 +56,7 @@ class SqlContext {
Table getTable(PersistentPropertyPathExtension path) {
SqlIdentifier tableAlias = path.getTableAlias();
Table table = Table.create(path.getTableName());
Table table = Table.create(path.getQualifiedTableName());
return tableAlias == null ? table : table.as(tableAlias);
}

View File

@@ -101,13 +101,13 @@ public class PersistentPropertyPathExtensionUnitTests {
assertSoftly(softly -> {
softly.assertThat(extPath(entity).getTableName()).isEqualTo(quoted("DUMMY_ENTITY"));
softly.assertThat(extPath("second").getTableName()).isEqualTo(quoted("SECOND"));
softly.assertThat(extPath("second.third2").getTableName()).isEqualTo(quoted("SECOND"));
softly.assertThat(extPath("second.third2.value").getTableName()).isEqualTo(quoted("SECOND"));
softly.assertThat(extPath("secondList.third2").getTableName()).isEqualTo(quoted("SECOND"));
softly.assertThat(extPath("secondList.third2.value").getTableName()).isEqualTo(quoted("SECOND"));
softly.assertThat(extPath("secondList").getTableName()).isEqualTo(quoted("SECOND"));
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"));
});
}

View File

@@ -23,8 +23,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
import org.springframework.data.relational.core.dialect.AnsiDialect;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.relational.core.dialect.AnsiDialect;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
@@ -37,9 +37,9 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
* @author Greg Turnquist
* @author Mark Paluch
*/
public class SqlGeneratorFixedNamingStrategyUnitTests {
class SqlGeneratorFixedNamingStrategyUnitTests {
final NamingStrategy fixedCustomTablePrefixStrategy = new NamingStrategy() {
private final NamingStrategy fixedCustomTablePrefixStrategy = new NamingStrategy() {
@Override
public String getSchema() {
@@ -57,7 +57,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
};
final NamingStrategy upperCaseLowerCaseStrategy = new NamingStrategy() {
private final NamingStrategy upperCaseLowerCaseStrategy = new NamingStrategy() {
@Override
public String getTableName(Class<?> type) {
@@ -73,7 +73,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
private RelationalMappingContext context = new JdbcMappingContext();
@Test // DATAJDBC-107
public void findOneWithOverriddenFixedTableName() {
void findOneWithOverriddenFixedTableName() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
@@ -96,7 +96,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-107
public void findOneWithUppercasedTablesAndLowercasedColumns() {
void findOneWithUppercasedTablesAndLowercasedColumns() {
SqlGenerator sqlGenerator = configureSqlGenerator(upperCaseLowerCaseStrategy);
@@ -115,7 +115,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-107
public void cascadingDeleteFirstLevel() {
void cascadingDeleteFirstLevel() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
@@ -126,7 +126,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-107
public void cascadingDeleteAllSecondLevel() {
void cascadingDeleteAllSecondLevel() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
@@ -141,7 +141,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-107
public void deleteAll() {
void deleteAll() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
@@ -151,7 +151,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-107
public void cascadingDeleteAllFirstLevel() {
void cascadingDeleteAllFirstLevel() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
@@ -162,7 +162,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-107
public void cascadingDeleteSecondLevel() {
void cascadingDeleteSecondLevel() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
@@ -177,7 +177,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
}
@Test // DATAJDBC-113
public void deleteByList() {
void deleteByList() {
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);

View File

@@ -26,6 +26,7 @@ import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.data.annotation.Version;
@@ -43,7 +44,6 @@ import org.springframework.data.relational.core.dialect.PostgresDialect;
import org.springframework.data.relational.core.dialect.SqlServerDialect;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.DefaultNamingStrategy;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
@@ -78,8 +78,8 @@ class SqlGeneratorUnitTests {
private static final Identifier BACKREF = Identifier.of(unquoted("backref"), "some-value", String.class);
private final NamingStrategy namingStrategy = new PrefixingNamingStrategy();
private final RelationalMappingContext context = new JdbcMappingContext(namingStrategy);
private final PrefixingNamingStrategy namingStrategy = new PrefixingNamingStrategy();
private RelationalMappingContext context = new JdbcMappingContext(namingStrategy);
private final JdbcConverter converter = new BasicJdbcConverter(context, (identifier, path) -> {
throw new UnsupportedOperationException();
});
@@ -749,7 +749,6 @@ class SqlGeneratorUnitTests {
@Test // DATAJDBC-340
void noColumnForReferencedEntity() {
assertThat(generatedColumn("ref", DummyEntity.class)).isNull();
}
@@ -867,18 +866,19 @@ class SqlGeneratorUnitTests {
@Test // GH-1161
void backReferenceShouldConsiderRenamedParent() {
context.setForeignKeyNaming(APPLY_RENAMING);
namingStrategy.setForeignKeyNaming(APPLY_RENAMING);
context = new JdbcMappingContext(namingStrategy);
String sql = sqlGenerator.createDeleteInByPath(getPath("ref", RenamedDummy.class));
assertThat(sql).isEqualTo("DELETE FROM referenced_entity WHERE referenced_entity.renamed IN (:ids)");
}
@Test // GH-1161
void backReferenceShouldIgnoreRenamedParent() {
context.setForeignKeyNaming(IGNORE_RENAMING);
namingStrategy.setForeignKeyNaming(IGNORE_RENAMING);
context = new JdbcMappingContext(namingStrategy);
String sql = sqlGenerator.createDeleteInByPath(getPath("ref", RenamedDummy.class));
@@ -888,26 +888,30 @@ class SqlGeneratorUnitTests {
@Test // GH-1161
void keyColumnShouldConsiderRenamedParent() {
context.setForeignKeyNaming(APPLY_RENAMING);
SqlGenerator sqlGenerator = createSqlGenerator(ReferencedEntity.class);
String sql = sqlGenerator.getFindAllByProperty(Identifier.of(unquoted("parentId"), 23, RenamedDummy.class), getPath("ref", RenamedDummy.class));
namingStrategy.setForeignKeyNaming(APPLY_RENAMING);
context = new JdbcMappingContext(namingStrategy);
assertThat(sql)
.contains("referenced_entity.renamed_key AS renamed_key", "WHERE referenced_entity.parentId");
SqlGenerator sqlGenerator = createSqlGenerator(ReferencedEntity.class);
String sql = sqlGenerator.getFindAllByProperty(Identifier.of(unquoted("parentId"), 23, RenamedDummy.class),
getPath("ref", RenamedDummy.class));
assertThat(sql).contains("referenced_entity.renamed_key AS renamed_key", "WHERE referenced_entity.parentId");
}
@Test // GH-1161
void keyColumnShouldIgnoreRenamedParent() {
context.setForeignKeyNaming(IGNORE_RENAMING);
namingStrategy.setForeignKeyNaming(IGNORE_RENAMING);
context = new JdbcMappingContext(namingStrategy);
SqlGenerator sqlGenerator = createSqlGenerator(ReferencedEntity.class);
String sql = sqlGenerator.getFindAllByProperty(Identifier.of(unquoted("parentId"), 23, RenamedDummy.class), getPath("ref", RenamedDummy.class));
String sql = sqlGenerator.getFindAllByProperty(Identifier.of(unquoted("parentId"), 23, RenamedDummy.class),
getPath("ref", RenamedDummy.class));
assertThat(sql)
.contains("referenced_entity.renamed_dummy_key AS renamed_dummy_key", "WHERE referenced_entity.parentId");
assertThat(sql).contains("referenced_entity.renamed_dummy_key AS renamed_dummy_key",
"WHERE referenced_entity.parentId");
}
@Nullable
private SqlIdentifier getAlias(Object maybeAliased) {
@@ -931,7 +935,8 @@ class SqlGeneratorUnitTests {
@SuppressWarnings("unused")
static class DummyEntity {
@Column("id1") @Id Long id;
@Column("id1")
@Id Long id;
String name;
ReferencedEntity ref;
Set<Element> elements;
@@ -1018,7 +1023,8 @@ class SqlGeneratorUnitTests {
// these column names behave like single double quote in the name since the get quoted and then doubling the double
// quote escapes it.
@Id @Column("test\"\"_@id") Long id;
@Id
@Column("test\"\"_@id") Long id;
@Column("test\"\"_@123") String name;
}

View File

@@ -277,7 +277,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
@Override
public SqlIdentifier getTableName(Class<?> type) {
return getRequiredPersistentEntity(type).getFullTableName();
return getRequiredPersistentEntity(type).getQualifiedTableName();
}
@Override

View File

@@ -465,7 +465,7 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
Assert.notNull(entity, "Entity must not be null");
return doInsert(entity, getRequiredEntity(entity).getFullTableName());
return doInsert(entity, getRequiredEntity(entity).getQualifiedTableName());
}
<T> Mono<T> doInsert(T entity, SqlIdentifier tableName) {
@@ -564,7 +564,7 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
Assert.notNull(entity, "Entity must not be null");
return doUpdate(entity, getRequiredEntity(entity).getFullTableName());
return doUpdate(entity, getRequiredEntity(entity).getQualifiedTableName());
}
private <T> Mono<T> doUpdate(T entity, SqlIdentifier tableName) {
@@ -644,13 +644,13 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
private <T> String formatOptimisticLockingExceptionMessage(T entity, RelationalPersistentEntity<T> persistentEntity) {
return String.format("Failed to update table [%s]; Version does not match for row with Id [%s]",
persistentEntity.getFullTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier());
persistentEntity.getQualifiedTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier());
}
private <T> String formatTransientEntityExceptionMessage(T entity, RelationalPersistentEntity<T> persistentEntity) {
return String.format("Failed to update table [%s]; Row with Id [%s] does not exist",
persistentEntity.getFullTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier());
persistentEntity.getQualifiedTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier());
}
@SuppressWarnings("unchecked")
@@ -744,14 +744,14 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
}
SqlIdentifier getTableName(Class<?> entityClass) {
return getRequiredEntity(entityClass).getFullTableName();
return getRequiredEntity(entityClass).getQualifiedTableName();
}
SqlIdentifier getTableNameOrEmpty(Class<?> entityClass) {
RelationalPersistentEntity<?> entity = this.mappingContext.getPersistentEntity(entityClass);
return entity != null ? entity.getFullTableName() : SqlIdentifier.EMPTY;
return entity != null ? entity.getQualifiedTableName() : SqlIdentifier.EMPTY;
}
private RelationalPersistentEntity<?> getRequiredEntity(Class<?> entityClass) {

View File

@@ -35,7 +35,6 @@ class CachingNamingStrategy implements NamingStrategy {
private final Map<RelationalPersistentProperty, String> columnNames = new ConcurrentHashMap<>();
private final Map<RelationalPersistentProperty, String> keyColumns = new ConcurrentHashMap<>();
private final Map<Class<?>, String> qualifiedTableNames = new ConcurrentReferenceHashMap<>();
private final Map<Class<?>, String> tableNames = new ConcurrentReferenceHashMap<>();
private final Lazy<String> schema;
@@ -83,8 +82,4 @@ class CachingNamingStrategy implements NamingStrategy {
return columnNames.computeIfAbsent(property, delegate::getColumnName);
}
@Override
public void setForeignKeyNaming(ForeignKeyNaming foreignKeyNaming) {
delegate.setForeignKeyNaming(foreignKeyNaming);
}
}

View File

@@ -15,26 +15,18 @@
*/
package org.springframework.data.relational.core.mapping;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.Assert;
/**
* The default naming strategy used by Spring Data Relational. Names are in SNAKE_CASE.
* The default naming strategy used by Spring Data Relational. Names are in {@code SNAKE_CASE}.
*
* @author Jens Schauder
* @since 2.4
* @since 3.0
*/
public class DefaultNamingStrategy implements NamingStrategy {
/**
* Since in most cases it doesn't make sense to have more than one {@link NamingStrategy} use of this instance is
* recommended.
*/
public static NamingStrategy INSTANCE = new DefaultNamingStrategy();
private ForeignKeyNaming foreignKeyNaming = ForeignKeyNaming.APPLY_RENAMING;
@Override
public void setForeignKeyNaming(ForeignKeyNaming foreignKeyNaming) {
Assert.notNull(foreignKeyNaming, "foreignKeyNaming must not be null");
@@ -51,19 +43,17 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override
public String getReverseColumnName(PersistentPropertyPathExtension path) {
RelationalPersistentEntity<?> leafEntity = path.getIdDefiningParentPath().getLeafEntity();
RelationalPersistentEntity<?> leafEntity = path.getIdDefiningParentPath().getRequiredLeafEntity();
return getColumnNameReferencing(leafEntity);
}
private String getColumnNameReferencing(RelationalPersistentEntity<?> leafEntity) {
Assert.state(leafEntity != null, "Leaf Entity must not be null.");
if (foreignKeyNaming == ForeignKeyNaming.IGNORE_RENAMING) {
return getTableName(leafEntity.getType());
}
return leafEntity.getSimpleTableName().getReference();
return leafEntity.getTableName().getReference();
}
}

View File

@@ -41,8 +41,12 @@ public interface NamingStrategy {
*
* @deprecated use {@link DefaultNamingStrategy#INSTANCE} instead.
*/
@Deprecated(since = "2.4")
NamingStrategy INSTANCE = DefaultNamingStrategy.INSTANCE;
@Deprecated(since = "2.4") NamingStrategy INSTANCE = new DefaultNamingStrategy() {
@Override
public void setForeignKeyNaming(ForeignKeyNaming foreignKeyNaming) {
throw new UnsupportedOperationException("Cannot update immutable DefaultNamingStrategy");
}
};
/**
* Defaults to no schema.
@@ -78,19 +82,18 @@ public interface NamingStrategy {
/**
* For a reference A -&gt; B this is the name in the table for B which references A.
*
* @param property The property who's column name in the owner table is required
* @param property The property whose column name in the owner table is required
* @return a column name. Must not be {@code null}.
*/
default String getReverseColumnName(RelationalPersistentProperty property) {
Assert.notNull(property, "Property must not be null");
return property.getOwner().getSimpleTableName().getReference(IdentifierProcessing.NONE);
return property.getOwner().getTableName().getReference(IdentifierProcessing.NONE);
}
default String getReverseColumnName(PersistentPropertyPathExtension path) {
return getTableName(path.getIdDefiningParentPath().getLeafEntity().getType());
return getTableName(path.getIdDefiningParentPath().getRequiredLeafEntity().getType());
}
/**
@@ -105,12 +108,4 @@ public interface NamingStrategy {
return getReverseColumnName(property) + "_key";
}
/**
* Set the {@link ForeignKeyNaming} strategy used in this {@link NamingStrategy}.
*
* @param foreignKeyNaming the ForeignKeyNaming strategy to be used. Must not be {@literal null}.
* @since 2.4
*/
default void setForeignKeyNaming(ForeignKeyNaming foreignKeyNaming) {}
}

View File

@@ -138,6 +138,30 @@ public class PersistentPropertyPathExtension {
return path == null ? entity : context.getPersistentEntity(path.getRequiredLeafProperty().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.getRequiredLeafProperty().getActualType()));
}
return entity;
}
/**
* @return {@literal true} when this is an empty path or the path references an entity.
*/
@@ -230,10 +254,22 @@ public class PersistentPropertyPathExtension {
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();
@@ -442,10 +478,6 @@ public class PersistentPropertyPathExtension {
return getParentPath().assembleColumnName(suffix.transform(embeddedPrefix::concat));
}
private RelationalPersistentEntity<?> getRequiredLeafEntity() {
return path == null ? entity : context.getRequiredPersistentEntity(path.getRequiredLeafProperty().getActualType());
}
private SqlIdentifier prefixWithTableAlias(SqlIdentifier columnName) {
SqlIdentifier tableAlias = getTableAlias();

View File

@@ -36,13 +36,12 @@ public class RelationalMappingContext
private final NamingStrategy namingStrategy;
private boolean forceQuote = true;
private ForeignKeyNaming foreignKeyNaming = ForeignKeyNaming.APPLY_RENAMING;
/**
* Creates a new {@link RelationalMappingContext}.
*/
public RelationalMappingContext() {
this(NamingStrategy.INSTANCE);
this(new DefaultNamingStrategy());
}
/**
@@ -54,7 +53,6 @@ public class RelationalMappingContext
Assert.notNull(namingStrategy, "NamingStrategy must not be null");
namingStrategy.setForeignKeyNaming(foreignKeyNaming);
this.namingStrategy = new CachingNamingStrategy(namingStrategy);
setSimpleTypeHolder(SimpleTypeHolder.DEFAULT);
@@ -104,19 +102,4 @@ public class RelationalMappingContext
return this.namingStrategy;
}
/**
* Sets the {@link ForeignKeyNaming} to be used by this mapping context.
*
* @param foreignKeyNaming must not be {@literal null}.
* @since 2.4
*/
public void setForeignKeyNaming(ForeignKeyNaming foreignKeyNaming) {
Assert.notNull(foreignKeyNaming, "foreignKeyNaming must not be null");
this.foreignKeyNaming = foreignKeyNaming;
if (namingStrategy != null) {
namingStrategy.setForeignKeyNaming(foreignKeyNaming);
}
}
}

View File

@@ -24,36 +24,27 @@ import org.springframework.data.relational.core.sql.SqlIdentifier;
*
* @author Jens Schauder
* @author Oliver Gierke
* @author Mark Paluch
*/
public interface RelationalPersistentEntity<T> extends MutablePersistentEntity<T, RelationalPersistentProperty> {
/**
* Returns the name of the table backing the given entity.
* Returns the unqualified name of the table (i.e. without schema or owner) backing the given entity.
*
* @return the table name.
* @deprecated Use either {@link #getFullTableName()} or {@link #getSimpleTableName()}
*/
@Deprecated(since = "2.4")
SqlIdentifier getTableName();
/**
* Returns the name of the table backing the given entity, including the schema.
* Returns the qualified name of the table backing the given entity, including the schema.
*
* @return the table name including the schema if there is any specified.
* @since 2.4
* @since 3.0
*/
default SqlIdentifier getFullTableName() {
default SqlIdentifier getQualifiedTableName() {
return getTableName();
}
/**
* Returns the name of the table backing the given entity, without any schema.
*
* @return the table name.
* @since 2.4
*/
SqlIdentifier getSimpleTableName();
/**
* Returns the column representing the identifier.
*

View File

@@ -51,15 +51,14 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
this.namingStrategy = namingStrategy;
this.tableName = Lazy.of(() -> Optional.ofNullable(findAnnotation(Table.class))
.map(Table::value)
.filter(StringUtils::hasText)
.map(this::createSqlIdentifier)
);
this.tableName = Lazy.of(() -> Optional.ofNullable(findAnnotation(Table.class)) //
.map(Table::value) //
.filter(StringUtils::hasText) //
.map(this::createSqlIdentifier));
this.schemaName = Lazy.of(() -> Optional.ofNullable(findAnnotation(Table.class))
.map(Table::schema)
.filter(StringUtils::hasText)
this.schemaName = Lazy.of(() -> Optional.ofNullable(findAnnotation(Table.class)) //
.map(Table::schema) //
.filter(StringUtils::hasText) //
.map(this::createSqlIdentifier));
}
@@ -81,11 +80,15 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
@Override
public SqlIdentifier getTableName() {
return getFullTableName();
Optional<SqlIdentifier> explicitlySpecifiedTableName = tableName.get();
SqlIdentifier schemalessTableIdentifier = createDerivedSqlIdentifier(namingStrategy.getTableName(getType()));
return explicitlySpecifiedTableName.orElse(schemalessTableIdentifier);
}
@Override
public SqlIdentifier getFullTableName() {
public SqlIdentifier getQualifiedTableName() {
SqlIdentifier schema = determineCurrentEntitySchema();
Optional<SqlIdentifier> explicitlySpecifiedTableName = tableName.get();
@@ -96,32 +99,21 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
return explicitlySpecifiedTableName.orElse(schemalessTableIdentifier);
}
return explicitlySpecifiedTableName
.map(sqlIdentifier -> SqlIdentifier.from(schema, sqlIdentifier))
return explicitlySpecifiedTableName.map(sqlIdentifier -> SqlIdentifier.from(schema, sqlIdentifier))
.orElse(SqlIdentifier.from(schema, schemalessTableIdentifier));
}
@Override
public SqlIdentifier getSimpleTableName() {
Optional<SqlIdentifier> explicitlySpecifiedTableName = tableName.get();
SqlIdentifier schemalessTableIdentifier = createDerivedSqlIdentifier(namingStrategy.getTableName(getType()));
return explicitlySpecifiedTableName.orElse(schemalessTableIdentifier);
}
/**
* @return {@link SqlIdentifier} representing the current entity schema. If the schema is not specified, neither
* explicitly, nor via {@link NamingStrategy}, then return {@link null}
* explicitly, nor via {@link NamingStrategy}, then return {@link null}
*/
@Nullable
private SqlIdentifier determineCurrentEntitySchema() {
Optional<SqlIdentifier> explicitlySpecifiedSchema = schemaName.get();
return explicitlySpecifiedSchema.orElseGet(
() -> StringUtils.hasText(namingStrategy.getSchema())
? createDerivedSqlIdentifier(namingStrategy.getSchema())
: null);
() -> StringUtils.hasText(namingStrategy.getSchema()) ? createDerivedSqlIdentifier(namingStrategy.getSchema())
: null);
}
@Override

View File

@@ -50,7 +50,7 @@ public class SimpleRelationalEntityMetadata<T> implements RelationalEntityMetada
}
public SqlIdentifier getTableName() {
return tableEntity.getFullTableName();
return tableEntity.getQualifiedTableName();
}
public RelationalPersistentEntity<?> getTableEntity() {

View File

@@ -87,7 +87,7 @@ public class MappingRelationalEntityInformation<T, ID> extends PersistentEntityI
}
public SqlIdentifier getTableName() {
return customTableName == null ? entityMetadata.getFullTableName() : customTableName;
return customTableName == null ? entityMetadata.getQualifiedTableName() : customTableName;
}
public String getIdAttribute() {

View File

@@ -32,55 +32,55 @@ import org.springframework.data.relational.core.sql.SqlIdentifier;
* @author Mark Paluch
* @author Mikhail Polivakha
*/
public class RelationalPersistentEntityImplUnitTests {
class RelationalPersistentEntityImplUnitTests {
RelationalMappingContext mappingContext = new RelationalMappingContext();
private RelationalMappingContext mappingContext = new RelationalMappingContext();
@Test // DATAJDBC-106
public void discoversAnnotatedTableName() {
void discoversAnnotatedTableName() {
RelationalPersistentEntity<?> entity = mappingContext.getPersistentEntity(DummySubEntity.class);
RelationalPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(DummySubEntity.class);
assertThat(entity.getTableName()).isEqualTo(quoted("dummy_sub_entity"));
assertThat(entity.getFullTableName()).isEqualTo(quoted("dummy_sub_entity"));
assertThat(entity.getSimpleTableName()).isEqualTo(quoted("dummy_sub_entity"));
assertThat(entity.getQualifiedTableName()).isEqualTo(quoted("dummy_sub_entity"));
assertThat(entity.getTableName()).isEqualTo(quoted("dummy_sub_entity"));
}
@Test // DATAJDBC-294
public void considerIdColumnName() {
void considerIdColumnName() {
RelationalPersistentEntity<?> entity = mappingContext.getPersistentEntity(DummySubEntity.class);
RelationalPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(DummySubEntity.class);
assertThat(entity.getIdColumn()).isEqualTo(quoted("renamedId"));
}
@Test // DATAJDBC-296
public void emptyTableAnnotationFallsBackToNamingStrategy() {
void emptyTableAnnotationFallsBackToNamingStrategy() {
RelationalPersistentEntity<?> entity = mappingContext.getPersistentEntity(DummyEntityWithEmptyAnnotation.class);
RelationalPersistentEntity<?> entity = mappingContext
.getRequiredPersistentEntity(DummyEntityWithEmptyAnnotation.class);
assertThat(entity.getTableName()).isEqualTo(quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION"));
assertThat(entity.getFullTableName()).isEqualTo(quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION"));
assertThat(entity.getSimpleTableName()).isEqualTo(quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION"));
assertThat(entity.getQualifiedTableName()).isEqualTo(quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION"));
assertThat(entity.getTableName()).isEqualTo(quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION"));
}
@Test // DATAJDBC-491
public void namingStrategyWithSchemaReturnsCompositeTableName() {
void namingStrategyWithSchemaReturnsCompositeTableName() {
mappingContext = new RelationalMappingContext(NamingStrategyWithSchema.INSTANCE);
RelationalPersistentEntity<?> entity = mappingContext.getPersistentEntity(DummyEntityWithEmptyAnnotation.class);
RelationalPersistentEntity<?> entity = mappingContext
.getRequiredPersistentEntity(DummyEntityWithEmptyAnnotation.class);
SqlIdentifier simpleExpected = quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION");
SqlIdentifier fullExpected = SqlIdentifier.from(quoted("MY_SCHEMA"), simpleExpected);
assertThat(entity.getQualifiedTableName())
.isEqualTo(fullExpected);
assertThat(entity.getTableName())
.isEqualTo(fullExpected);
assertThat(entity.getFullTableName())
.isEqualTo(fullExpected);
assertThat(entity.getSimpleTableName())
.isEqualTo(simpleExpected);
assertThat(entity.getTableName().toSql(IdentifierProcessing.ANSI))
assertThat(entity.getQualifiedTableName().toSql(IdentifierProcessing.ANSI))
.isEqualTo("\"MY_SCHEMA\".\"DUMMY_ENTITY_WITH_EMPTY_ANNOTATION\"");
}
@@ -88,34 +88,32 @@ public class RelationalPersistentEntityImplUnitTests {
void testRelationalPersistentEntitySchemaNameChoice() {
mappingContext = new RelationalMappingContext(NamingStrategyWithSchema.INSTANCE);
RelationalPersistentEntity<?> entity = mappingContext.getPersistentEntity(EntityWithSchemaAndName.class);
RelationalPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(EntityWithSchemaAndName.class);
SqlIdentifier simpleExpected = quoted("I_AM_THE_SENATE");
SqlIdentifier expected = SqlIdentifier.from(quoted("DART_VADER"), simpleExpected);
assertThat(entity.getTableName()).isEqualTo(expected);
assertThat(entity.getFullTableName()).isEqualTo(expected);
assertThat(entity.getSimpleTableName()).isEqualTo(simpleExpected);
assertThat(entity.getQualifiedTableName()).isEqualTo(expected);
assertThat(entity.getTableName()).isEqualTo(simpleExpected);
}
@Test // GH-1099
void specifiedSchemaGetsCombinedWithNameFromNamingStrategy() {
RelationalPersistentEntity<?> entity = mappingContext.getPersistentEntity(EntityWithSchema.class);
RelationalPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(EntityWithSchema.class);
SqlIdentifier simpleExpected = quoted("ENTITY_WITH_SCHEMA");
SqlIdentifier expected = SqlIdentifier.from(quoted("ANAKYN_SKYWALKER"), simpleExpected);
assertThat(entity.getTableName()).isEqualTo(expected);
assertThat(entity.getFullTableName()).isEqualTo(expected);
assertThat(entity.getSimpleTableName()).isEqualTo(simpleExpected);
assertThat(entity.getQualifiedTableName()).isEqualTo(expected);
assertThat(entity.getTableName()).isEqualTo(simpleExpected);
}
@Table(schema = "ANAKYN_SKYWALKER")
static class EntityWithSchema {
private static class EntityWithSchema {
@Id private Long id;
}
@Table(schema = "DART_VADER", name = "I_AM_THE_SENATE")
static class EntityWithSchemaAndName {
private static class EntityWithSchemaAndName {
@Id private Long id;
}