Skip to content

Commit d12146d

Browse files
mipo256schauder
authored andcommitted
Support specification of a schema in Column annotations.
Closes #1099 Original pull request #1108
1 parent cdff385 commit d12146d

File tree

3 files changed

+86
-14
lines changed

3 files changed

+86
-14
lines changed

spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImpl.java

+36-13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.Optional;
1919

20+
import org.jetbrains.annotations.NotNull;
2021
import org.springframework.data.mapping.model.BasicPersistentEntity;
2122
import org.springframework.data.relational.core.sql.SqlIdentifier;
2223
import org.springframework.data.util.Lazy;
@@ -29,12 +30,14 @@
2930
* @author Jens Schauder
3031
* @author Greg Turnquist
3132
* @author Bastian Wilhelm
33+
* @author Mikhail Polivakha
3234
*/
3335
class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, RelationalPersistentProperty>
3436
implements RelationalPersistentEntity<T> {
3537

3638
private final NamingStrategy namingStrategy;
3739
private final Lazy<Optional<SqlIdentifier>> tableName;
40+
private final Lazy<Optional<SqlIdentifier>> schemaName;
3841
private boolean forceQuote = true;
3942

4043
/**
@@ -43,16 +46,20 @@ class RelationalPersistentEntityImpl<T> extends BasicPersistentEntity<T, Relatio
4346
* @param information must not be {@literal null}.
4447
*/
4548
RelationalPersistentEntityImpl(TypeInformation<T> information, NamingStrategy namingStrategy) {
46-
4749
super(information);
50+
final Optional<Table> optionalTableAnnotation = Optional.ofNullable(findAnnotation(Table.class));
4851

4952
this.namingStrategy = namingStrategy;
50-
this.tableName = Lazy.of(() -> Optional.ofNullable( //
51-
findAnnotation(Table.class)) //
52-
.map(Table::value) //
53-
.filter(StringUtils::hasText) //
54-
.map(this::createSqlIdentifier) //
53+
this.tableName = Lazy.of(() -> optionalTableAnnotation
54+
.map(Table::value)
55+
.filter(StringUtils::hasText)
56+
.map(this::createSqlIdentifier)
5557
);
58+
59+
this.schemaName = Lazy.of(() -> optionalTableAnnotation
60+
.map(Table::schema)
61+
.filter(StringUtils::hasText)
62+
.map(this::createSqlIdentifier));
5663
}
5764

5865
private SqlIdentifier createSqlIdentifier(String name) {
@@ -77,14 +84,30 @@ public void setForceQuote(boolean forceQuote) {
7784
*/
7885
@Override
7986
public SqlIdentifier getTableName() {
80-
return tableName.get().orElseGet(() -> {
81-
82-
String schema = namingStrategy.getSchema();
83-
SqlIdentifier tableName = createDerivedSqlIdentifier(namingStrategy.getTableName(getType()));
87+
final Optional<SqlIdentifier> schema = determineCurrentEntitySchema();
88+
final Optional<SqlIdentifier> explicitlySpecifiedTableName = tableName.get();
89+
if (schema.isPresent()) {
90+
return explicitlySpecifiedTableName
91+
.map(sqlIdentifier -> SqlIdentifier.from(schema.get(), sqlIdentifier))
92+
.orElse(SqlIdentifier.from(schema.get(), createDerivedSqlIdentifier(namingStrategy.getTableName(getType()))));
93+
} else {
94+
return explicitlySpecifiedTableName.orElse(createDerivedSqlIdentifier(namingStrategy.getTableName(getType())));
95+
}
96+
}
8497

85-
return StringUtils.hasText(schema) ? SqlIdentifier.from(createDerivedSqlIdentifier(schema), tableName)
86-
: tableName;
87-
});
98+
/**
99+
* @return Optional of {@link SqlIdentifier} representing the current entity schema. If the schema is not specified neither
100+
* explicitly, nor via {@link NamingStrategy}, then return {@link Optional#empty()}
101+
*/
102+
@NotNull
103+
private Optional<SqlIdentifier> determineCurrentEntitySchema() {
104+
final Optional<SqlIdentifier> explicitlySpecifiedSchema = schemaName.get();
105+
if (explicitlySpecifiedSchema.isPresent()) {
106+
return explicitlySpecifiedSchema;
107+
}
108+
return StringUtils.hasText(namingStrategy.getSchema())
109+
? Optional.of(createDerivedSqlIdentifier(namingStrategy.getSchema()))
110+
: Optional.empty();
88111
}
89112

90113
/*

spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Table.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.relational.core.mapping;
1717

18+
import org.springframework.core.annotation.AliasFor;
19+
1820
import java.lang.annotation.Documented;
1921
import java.lang.annotation.ElementType;
2022
import java.lang.annotation.Inherited;
@@ -27,6 +29,7 @@
2729
*
2830
* @author Kazuki Shimizu
2931
* @author Bastian Wilhelm
32+
* @author Mikhail Polivakha
3033
*/
3134
@Retention(RetentionPolicy.RUNTIME)
3235
@Target(ElementType.TYPE)
@@ -37,5 +40,23 @@
3740
/**
3841
* The mapping table name.
3942
*/
43+
@AliasFor("name")
4044
String value() default "";
41-
}
45+
46+
/**
47+
* The mapping table name.
48+
*/
49+
@AliasFor("value")
50+
String name() default "";
51+
52+
/**
53+
* Name of the schema (or user, for example in case of oracle), in which this table resides in
54+
* The behavior is the following: <br/>
55+
* If the {@link Table#schema()} is specified, then it will be
56+
* used as a schema of current table, i.e. as a prefix to the name of the table, which can
57+
* be specified in {@link Table#value()}. <br/>
58+
* If the {@link Table#schema()} is not specified, then spring data will assume the default schema,
59+
* The default schema itself can be provided by the means of {@link NamingStrategy#getSchema()}
60+
*/
61+
String schema() default "";
62+
}

spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntityImplUnitTests.java

+28
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
* @author Kazuki Shimizu
3232
* @author Bastian Wilhelm
3333
* @author Mark Paluch
34+
* @author Mikhail Polivakha
3435
*/
3536
public class RelationalPersistentEntityImplUnitTests {
3637

@@ -72,6 +73,33 @@ public void namingStrategyWithSchemaReturnsCompositeTableName() {
7273
.isEqualTo("\"MY_SCHEMA\".\"DUMMY_ENTITY_WITH_EMPTY_ANNOTATION\"");
7374
}
7475

76+
@Test // DATAJDBC-1099
77+
void testRelationalPersistentEntitySchemaNameChoice() {
78+
mappingContext = new RelationalMappingContext(NamingStrategyWithSchema.INSTANCE);
79+
final RelationalPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(EntityWithExplicitSchema.class);
80+
final SqlIdentifier tableName = persistentEntity.getTableName();
81+
assertThat(tableName).isEqualTo(SqlIdentifier.from(SqlIdentifier.quoted("DART_VADER"), quoted("I_AM_THE_SENATE")));
82+
assertThat(tableName.toString()).isEqualTo("\"DART_VADER\".\"I_AM_THE_SENATE\"");
83+
}
84+
85+
@Test // DATAJDBC-1099
86+
void testRelationalPersistentEntityTableOnlySchemaSpecified() {
87+
final RelationalPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(EntityWithSchemaFromNamingStrategy.class);
88+
final SqlIdentifier tableName = persistentEntity.getTableName();
89+
assertThat(tableName).isEqualTo(SqlIdentifier.from(quoted("ANAKYN_SKYWALKER"), quoted("ENTITY_WITH_SCHEMA_FROM_NAMING_STRATEGY")));
90+
assertThat(tableName.toString()).isEqualTo("\"ANAKYN_SKYWALKER\".\"ENTITY_WITH_SCHEMA_FROM_NAMING_STRATEGY\"");
91+
}
92+
93+
@Table(schema = "ANAKYN_SKYWALKER")
94+
static class EntityWithSchemaFromNamingStrategy {
95+
@Id private Long id;
96+
}
97+
98+
@Table(schema = "DART_VADER", name = "I_AM_THE_SENATE")
99+
static class EntityWithExplicitSchema {
100+
@Id private Long id;
101+
}
102+
75103
@Table("dummy_sub_entity")
76104
static class DummySubEntity {
77105
@Id @Column("renamedId") Long id;

0 commit comments

Comments
 (0)