schema;
@@ -82,4 +81,5 @@ public String getSchema() {
public String getColumnName(RelationalPersistentProperty property) {
return columnNames.computeIfAbsent(property, delegate::getColumnName);
}
+
}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DefaultNamingStrategy.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DefaultNamingStrategy.java
new file mode 100644
index 0000000000..e22cde1d86
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/DefaultNamingStrategy.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2022 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 org.springframework.util.Assert;
+
+/**
+ * The default naming strategy used by Spring Data Relational. Names are in {@code SNAKE_CASE}.
+ *
+ * @author Jens Schauder
+ * @since 3.0
+ */
+public class DefaultNamingStrategy implements NamingStrategy {
+
+ private ForeignKeyNaming foreignKeyNaming = ForeignKeyNaming.APPLY_RENAMING;
+
+ public void setForeignKeyNaming(ForeignKeyNaming foreignKeyNaming) {
+
+ Assert.notNull(foreignKeyNaming, "foreignKeyNaming must not be null");
+
+ this.foreignKeyNaming = foreignKeyNaming;
+ }
+
+ @Override
+ public String getReverseColumnName(RelationalPersistentProperty property) {
+
+ return getColumnNameReferencing(property.getOwner());
+ }
+
+ @Override
+ public String getReverseColumnName(PersistentPropertyPathExtension path) {
+
+ RelationalPersistentEntity> leafEntity = path.getIdDefiningParentPath().getRequiredLeafEntity();
+
+ return getColumnNameReferencing(leafEntity);
+ }
+
+ private String getColumnNameReferencing(RelationalPersistentEntity> leafEntity) {
+
+ if (foreignKeyNaming == ForeignKeyNaming.IGNORE_RENAMING) {
+ return getTableName(leafEntity.getType());
+ }
+
+ return leafEntity.getTableName().getReference();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/ForeignKeyNaming.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/ForeignKeyNaming.java
new file mode 100644
index 0000000000..e5f98123f1
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/ForeignKeyNaming.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 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;
+
+/**
+ * Enum for determining how the names of back references should get generated.
+ *
+ * @author Jens Schauder
+ * @since 2.4
+ */
+public enum ForeignKeyNaming {
+ /**
+ * This strategy takes names specified via {@link Table} annotation into account.
+ */
+ APPLY_RENAMING,
+ /**
+ * This strategy does not take names specified via {@link Table} annotation into account.
+ */
+ IGNORE_RENAMING
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java
index bc1fdaeabc..05b6b227fc 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/NamingStrategy.java
@@ -38,8 +38,15 @@ public interface NamingStrategy {
* Empty implementation of the interface utilizing only the default implementation.
*
* Using this avoids creating essentially the same class over and over again.
+ *
+ * @deprecated use {@link DefaultNamingStrategy#INSTANCE} instead.
*/
- NamingStrategy INSTANCE = new NamingStrategy() {};
+ @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.
@@ -75,7 +82,7 @@ default String getColumnName(RelationalPersistentProperty property) {
/**
* For a reference A -> 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) {
@@ -86,8 +93,7 @@ default String getReverseColumnName(RelationalPersistentProperty property) {
}
default String getReverseColumnName(PersistentPropertyPathExtension path) {
-
- return getTableName(path.getIdDefiningParentPath().getLeafEntity().getType());
+ return getTableName(path.getIdDefiningParentPath().getRequiredLeafEntity().getType());
}
/**
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java
index 068f198ddb..865d527f15 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/PersistentPropertyPathExtension.java
@@ -138,6 +138,30 @@ public RelationalPersistentEntity> getLeafEntity() {
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,21 @@ public PersistentPropertyPathExtension 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}.
+ */
+ 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 +477,6 @@ private SqlIdentifier assembleColumnName(SqlIdentifier suffix) {
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();
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java
index 11a43248de..f46b43841f 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java
@@ -41,7 +41,7 @@ public class RelationalMappingContext
* Creates a new {@link RelationalMappingContext}.
*/
public RelationalMappingContext() {
- this(NamingStrategy.INSTANCE);
+ this(new DefaultNamingStrategy());
}
/**
@@ -101,4 +101,5 @@ protected RelationalPersistentProperty createPersistentProperty(Property propert
public NamingStrategy getNamingStrategy() {
return this.namingStrategy;
}
+
}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java
index 15b3234763..8d3f8f96ea 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java
@@ -24,20 +24,32 @@
*
* @author Jens Schauder
* @author Oliver Gierke
+ * @author Mark Paluch
*/
public interface RelationalPersistentEntity extends MutablePersistentEntity {
/**
- * 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.
*/
SqlIdentifier getTableName();
+ /**
+ * 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 3.0
+ */
+ default SqlIdentifier getQualifiedTableName() {
+ return getTableName();
+ }
+
/**
* Returns the column representing the identifier.
*
* @return will never be {@literal null}.
*/
SqlIdentifier getIdColumn();
+
}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java
index 9021f6a9e3..0ffccabed8 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java
@@ -51,16 +51,11 @@ class RelationalPersistentEntityImpl extends BasicPersistentEntity 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)
- .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).map(this::createSqlIdentifier));
}
private SqlIdentifier createSqlIdentifier(String name) {
@@ -82,32 +77,39 @@ public void setForceQuote(boolean forceQuote) {
@Override
public SqlIdentifier getTableName() {
+ Optional explicitlySpecifiedTableName = tableName.get();
+ SqlIdentifier schemalessTableIdentifier = createDerivedSqlIdentifier(namingStrategy.getTableName(getType()));
+
+ return explicitlySpecifiedTableName.orElse(schemalessTableIdentifier);
+ }
+
+ @Override
+ public SqlIdentifier getQualifiedTableName() {
+
SqlIdentifier schema = determineCurrentEntitySchema();
Optional explicitlySpecifiedTableName = tableName.get();
- final SqlIdentifier schemalessTableIdentifier = createDerivedSqlIdentifier(namingStrategy.getTableName(getType()));
+ SqlIdentifier schemalessTableIdentifier = createDerivedSqlIdentifier(namingStrategy.getTableName(getType()));
if (schema == null) {
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));
}
/**
* @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 explicitlySpecifiedSchema = schemaName.get();
return explicitlySpecifiedSchema.orElseGet(
- () -> StringUtils.hasText(namingStrategy.getSchema())
- ? createDerivedSqlIdentifier(namingStrategy.getSchema())
- : null);
+ () -> StringUtils.hasText(namingStrategy.getSchema()) ? createDerivedSqlIdentifier(namingStrategy.getSchema())
+ : null);
}
@Override
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java
index a633302a3d..89077b3a54 100755
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/SimpleRelationalEntityMetadata.java
@@ -50,7 +50,7 @@ public Class getJavaType() {
}
public SqlIdentifier getTableName() {
- return tableEntity.getTableName();
+ return tableEntity.getQualifiedTableName();
}
public RelationalPersistentEntity> getTableEntity() {
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java
index 0af57a0db7..e5ea18f9d5 100755
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/support/MappingRelationalEntityInformation.java
@@ -87,7 +87,7 @@ private MappingRelationalEntityInformation(RelationalPersistentEntity entity,
}
public SqlIdentifier getTableName() {
- return customTableName == null ? entityMetadata.getTableName() : customTableName;
+ return customTableName == null ? entityMetadata.getQualifiedTableName() : customTableName;
}
public String getIdAttribute() {
diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java
index 8008a3c96c..13400dff99 100644
--- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java
+++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java
@@ -32,43 +32,55 @@
* @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.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.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(SqlIdentifier.from(quoted("MY_SCHEMA"), quoted("DUMMY_ENTITY_WITH_EMPTY_ANNOTATION")));
- assertThat(entity.getTableName().toSql(IdentifierProcessing.ANSI))
+ .isEqualTo(simpleExpected);
+
+ assertThat(entity.getQualifiedTableName().toSql(IdentifierProcessing.ANSI))
.isEqualTo("\"MY_SCHEMA\".\"DUMMY_ENTITY_WITH_EMPTY_ANNOTATION\"");
}
@@ -76,30 +88,32 @@ public void namingStrategyWithSchemaReturnsCompositeTableName() {
void testRelationalPersistentEntitySchemaNameChoice() {
mappingContext = new RelationalMappingContext(NamingStrategyWithSchema.INSTANCE);
- RelationalPersistentEntity> persistentEntity = mappingContext.getPersistentEntity(EntityWithSchemaAndName.class);
-
- SqlIdentifier tableName = persistentEntity.getTableName();
+ RelationalPersistentEntity> entity = mappingContext.getRequiredPersistentEntity(EntityWithSchemaAndName.class);
- assertThat(tableName).isEqualTo(SqlIdentifier.from(SqlIdentifier.quoted("DART_VADER"), quoted("I_AM_THE_SENATE")));
+ SqlIdentifier simpleExpected = quoted("I_AM_THE_SENATE");
+ SqlIdentifier expected = SqlIdentifier.from(quoted("DART_VADER"), simpleExpected);
+ assertThat(entity.getQualifiedTableName()).isEqualTo(expected);
+ assertThat(entity.getTableName()).isEqualTo(simpleExpected);
}
@Test // GH-1099
void specifiedSchemaGetsCombinedWithNameFromNamingStrategy() {
- RelationalPersistentEntity> persistentEntity = mappingContext.getPersistentEntity(EntityWithSchema.class);
-
- SqlIdentifier tableName = persistentEntity.getTableName();
+ RelationalPersistentEntity> entity = mappingContext.getRequiredPersistentEntity(EntityWithSchema.class);
- assertThat(tableName).isEqualTo(SqlIdentifier.from(quoted("ANAKYN_SKYWALKER"), quoted("ENTITY_WITH_SCHEMA")));
+ SqlIdentifier simpleExpected = quoted("ENTITY_WITH_SCHEMA");
+ SqlIdentifier expected = SqlIdentifier.from(quoted("ANAKYN_SKYWALKER"), 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;
}
diff --git a/src/main/asciidoc/jdbc.adoc b/src/main/asciidoc/jdbc.adoc
index ac78ad9e02..940a48e33b 100644
--- a/src/main/asciidoc/jdbc.adoc
+++ b/src/main/asciidoc/jdbc.adoc
@@ -216,22 +216,23 @@ The properties of the following types are currently supported:
* References to other entities.
They are considered a one-to-one relationship, or an embedded type.
It is optional for one-to-one relationship entities to have an `id` attribute.
-The table of the referenced entity is expected to have an additional column named the same as the table of the referencing entity.
-You can change this name by implementing `NamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)`.
+The table of the referenced entity is expected to have an additional column with a name based on the referencing entity see <>.
Embedded entities do not need an `id`.
If one is present it gets ignored.
* `Set` is considered a one-to-many relationship.
-The table of the referenced entity is expected to have an additional column named the same as the table of the referencing entity.
-You can change this name by implementing `NamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)`.
+The table of the referenced entity is expected to have an additional column with a name based on the referencing entity see <>.
* `Map` is considered a qualified one-to-many relationship.
-The table of the referenced entity is expected to have two additional columns: One named the same as the table of the referencing entity for the foreign key and one with the same name and an additional `_key` suffix for the map key.
+The table of the referenced entity is expected to have two additional columns: One named based on the referencing entity for the foreign key (see <>) and one with the same name and an additional `_key` suffix for the map key.
You can change this behavior by implementing `NamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)` and `NamingStrategy.getKeyColumn(RelationalPersistentProperty property)`, respectively.
Alternatively you may annotate the attribute with `@MappedCollection(idColumn="your_column_name", keyColumn="your_key_column_name")`
* `List` is mapped as a `Map`.
+[[jdbc.entity-persistence.types.referenced-entities]]
+==== Referenced Entities
+
The handling of referenced entities is limited.
This is based on the idea of aggregate roots as described above.
If you reference another entity, that entity is, by definition, part of your aggregate.
@@ -240,10 +241,23 @@ This also means references are 1-1 or 1-n, but not n-1 or n-m.
If you have n-1 or n-m references, you are, by definition, dealing with two separate aggregates.
References between those may be encoded as simple `id` values, which map properly with Spring Data JDBC.
-A better way to encode these is to make them instances of `AggregateReference`.
+A better way to encode these, is to make them instances of `AggregateReference`.
An `AggregateReference` is a wrapper around an id value which marks that value as a reference to a different aggregate.
Also, the type of that aggregate is encoded in a type parameter.
+[[jdbc.entity-persistence.types.backrefs]]
+==== Back References
+
+All references in an aggregate result in a foreign key relationship in the opposite direction in the database.
+By default, the name of the foreign key column is the table name of the referencing entity.
+
+Alternatively you may choose to have them named by the entity name of the referencing entity ignoreing `@Table` annotations.
+You activate this behaviour by calling `setForeignKeyNaming(ForeignKeyNaming.IGNORE_RENAMING)` on the `RelationalMappingContext`.
+
+For `List` and `Map` references an additional column is required for holding the list index or map key. It is based on the foreign key column with an additional `_KEY` suffix.
+
+If you want a completely different way of naming these back references you may implement `NamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)` in a way that fits your needs.
+
.Declaring and setting an `AggregateReference`
====