DATAJDBC-131 - Basic support for Maps
Aggregate roots with properties of type java.util.Map get properly inserted, updated and deleted.
Known limitations:
- Naming strategy does not allow for multiple references via Set, Map or directly to the same entity.
- The table for the referenced Entity contains the column for the map key.
A workaround for that would be to manipulate the DbActions in the AggregateChange yourself.
This commit is contained in:
committed by
Greg Turnquist
parent
482f330f02
commit
b385f7f24f
@@ -29,7 +29,7 @@ public interface DataAccessStrategy {
|
||||
|
||||
<T> void insert(T instance, Class<T> domainType, Map<String, Object> additionalParameters);
|
||||
|
||||
<S> void update(S instance, Class<S> domainType);
|
||||
<T> void update(T instance, Class<T> domainType);
|
||||
|
||||
void delete(Object id, Class<?> domainType);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.data.jdbc.support.JdbcUtil;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||
@@ -71,7 +72,6 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses.
|
||||
*
|
||||
* Only suitable if this is the only access strategy in use.
|
||||
*/
|
||||
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, NamedParameterJdbcOperations operations,
|
||||
@@ -149,7 +149,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteAll(PropertyPath propertyPath) {
|
||||
public void deleteAll(PropertyPath propertyPath) {
|
||||
operations.getJdbcOperations().update(sql(propertyPath.getOwningType().getType()).createDeleteAllSql(propertyPath));
|
||||
}
|
||||
|
||||
@@ -193,14 +193,18 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> findAllByProperty(Object rootId, JdbcPersistentProperty property) {
|
||||
public Iterable findAllByProperty(Object rootId, JdbcPersistentProperty property) {
|
||||
|
||||
Class<?> actualType = property.getActualType();
|
||||
String findAllByProperty = sql(actualType).getFindAllByProperty(property.getReverseColumnName());
|
||||
boolean isMap = property.getTypeInformation().isMap();
|
||||
String findAllByProperty = sql(actualType).getFindAllByProperty(property.getReverseColumnName(),
|
||||
property.getKeyColumn());
|
||||
|
||||
MapSqlParameterSource parameter = new MapSqlParameterSource(property.getReverseColumnName(), rootId);
|
||||
|
||||
return (Iterable<T>) operations.query(findAllByProperty, parameter, getEntityRowMapper(actualType));
|
||||
return operations.query(findAllByProperty, parameter, isMap //
|
||||
? getMapEntityRowMapper(property) //
|
||||
: getEntityRowMapper(actualType));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -287,7 +291,12 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), conversions, context, accessStrategy);
|
||||
}
|
||||
|
||||
private RowMapper getMapEntityRowMapper(JdbcPersistentProperty property) {
|
||||
return new MapEntityRowMapper(getEntityRowMapper(property.getActualType()), property.getKeyColumn());
|
||||
}
|
||||
|
||||
private <T> MapSqlParameterSource createIdParameterSource(Object id, Class<T> domainType) {
|
||||
|
||||
return new MapSqlParameterSource("id",
|
||||
convert(id, getRequiredPersistentEntity(domainType).getRequiredIdProperty().getColumnType()));
|
||||
}
|
||||
@@ -313,5 +322,4 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
private SqlGenerator sql(Class<?> domainType) {
|
||||
return sqlGeneratorSource.getSqlGenerator(domainType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,13 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
private <T> Map<String, Object> createAdditionalColumnValues(Insert<T> insert) {
|
||||
|
||||
Map<String, Object> additionalColumnValues = new HashMap<>();
|
||||
addDependingOnInformation(insert, additionalColumnValues);
|
||||
additionalColumnValues.putAll(insert.getAdditionalValues());
|
||||
|
||||
return additionalColumnValues;
|
||||
}
|
||||
|
||||
private <T> void addDependingOnInformation(Insert<T> insert, Map<String, Object> additionalColumnValues) {
|
||||
DbAction dependingOn = insert.getDependingOn();
|
||||
|
||||
if (dependingOn != null) {
|
||||
@@ -88,7 +95,5 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
|
||||
additionalColumnValues.put(columnName, identifier);
|
||||
}
|
||||
return additionalColumnValues;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import lombok.NonNull;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
@@ -80,6 +81,11 @@ class EntityRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
if (Set.class.isAssignableFrom(property.getType())) {
|
||||
propertyAccessor.setProperty(property, accessStrategy.findAllByProperty(id, property));
|
||||
} else if (Map.class.isAssignableFrom(property.getType())) {
|
||||
|
||||
Iterable<Object> allByProperty = accessStrategy.findAllByProperty(id, property);
|
||||
IterableOfEntryToMapConverter converter = new IterableOfEntryToMapConverter();
|
||||
propertyAccessor.setProperty(property, converter.convert(allByProperty));
|
||||
} else {
|
||||
propertyAccessor.setProperty(property, readFrom(resultSet, property, ""));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalConverter;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A converter for creating a {@link Map} from an {@link Iterable<Map.Entry>}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable, Map> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map convert(Iterable source) {
|
||||
|
||||
HashMap result = new HashMap();
|
||||
|
||||
source.forEach(element -> {
|
||||
|
||||
if (!(element instanceof Entry)) {
|
||||
throw new IllegalArgumentException(String.format("Cannot convert %s to Map.Entry", element.getClass()));
|
||||
}
|
||||
|
||||
Entry entry = (Entry) element;
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to determine if the {@literal sourceType} can be converted to a {@link Map}. If this can not be determined,
|
||||
* because the sourceTyppe does not contain information about the element type it returns {@literal true}.
|
||||
*
|
||||
* @param sourceType {@link TypeDescriptor} to convert from.
|
||||
* @param targetType {@link TypeDescriptor} to convert to.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
Assert.notNull(sourceType, "Source type must not be null.");
|
||||
Assert.notNull(targetType, "Target type must not be null.");
|
||||
|
||||
if (!sourceType.isAssignableTo(TypeDescriptor.valueOf(Iterable.class)))
|
||||
return false;
|
||||
|
||||
TypeDescriptor elementDescriptor = sourceType.getElementTypeDescriptor();
|
||||
return elementDescriptor == null || elementDescriptor.isAssignableTo(TypeDescriptor.valueOf(Entry.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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 java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link RowMapper} that maps a row to a {@link Map.Entry} so an {@link Iterable} of those can be converted to a
|
||||
* {@link Map} using an {@link IterableOfEntryToMapConverter}. Creation of the {@literal value} part of the resulting
|
||||
* {@link Map.Entry} is delegated to a {@link RowMapper} provided in the constructor.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
class MapEntityRowMapper<T> implements RowMapper<Map.Entry<Object, T>> {
|
||||
|
||||
private final RowMapper<T> delegate;
|
||||
private final String keyColumn;
|
||||
|
||||
MapEntityRowMapper(RowMapper<T> delegate, String keyColumn) {
|
||||
|
||||
this.delegate = delegate;
|
||||
this.keyColumn = keyColumn;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map.Entry<Object, T> mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return new HashMap.SimpleEntry<>(rs.getObject(keyColumn), delegate.mapRow(rs, rowNum));
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.jdbc.core;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -88,8 +89,24 @@ class SqlGenerator {
|
||||
return findAllSql.get();
|
||||
}
|
||||
|
||||
String getFindAllByProperty(String columnName) {
|
||||
return String.format("%s WHERE %s = :%s", findAllSql.get(), columnName, columnName);
|
||||
/**
|
||||
* Returns a query for selecting all simple properties of an entity, including those for one-to-one relationships.
|
||||
* Results are limited to those rows referencing some other entity using the column specified by
|
||||
* {@literal columnName}. This is used to select values for a complex property ({@link Set}, {@link Map} ...) based on
|
||||
* a referencing entity.
|
||||
*
|
||||
* @param columnName name of the column of the FK back to the referencing entity.
|
||||
* @param keyColumn if the property is of type {@link Map} this column contains the map key.
|
||||
* @return a SQL String.
|
||||
*/
|
||||
String getFindAllByProperty(String columnName, String keyColumn) {
|
||||
|
||||
String baseSelect = (keyColumn != null) //
|
||||
? createSelectBuilder().column(cb -> cb.tableAlias(entity.getTableName()).column(keyColumn).as(keyColumn))
|
||||
.build()
|
||||
: getFindAll();
|
||||
|
||||
return String.format("%s WHERE %s = :%s", baseSelect, columnName, columnName);
|
||||
}
|
||||
|
||||
String getExists() {
|
||||
@@ -136,10 +153,19 @@ class SqlGenerator {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the columns to the provided {@link SelectBuilder} representing simplem properties, including those from
|
||||
* one-to-one relationships.
|
||||
*
|
||||
* @param builder The {@link SelectBuilder} to be modified.
|
||||
*/
|
||||
private void addColumnsAndJoinsForOneToOneReferences(SelectBuilder builder) {
|
||||
|
||||
for (JdbcPersistentProperty property : entity) {
|
||||
if (!property.isEntity() || Collection.class.isAssignableFrom(property.getType())) {
|
||||
if (!property.isEntity() //
|
||||
|| Collection.class.isAssignableFrom(property.getType()) //
|
||||
|| Map.class.isAssignableFrom(property.getType()) //
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.springframework.data.jdbc.core.conversion;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -40,6 +43,13 @@ public abstract class DbAction<T> {
|
||||
*/
|
||||
private final T entity;
|
||||
|
||||
/**
|
||||
* Key-value-pairs to specify additional values to be used with the statement which can't be obtained from the entity,
|
||||
* nor from {@link DbAction}s {@literal this} depends on. A used case are map keys, which need to be persisted with
|
||||
* the map value but aren't part of the value.
|
||||
*/
|
||||
private final Map<String, Object> additionalValues = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Another action, this action depends on. For example the insert for one entity might need the id of another entity,
|
||||
* which gets insert before this one. That action would be referenced by this property, so that the id becomes
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.conversion;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
|
||||
@@ -56,7 +60,7 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
|
||||
Insert<Object> insert = DbAction.insert(o, dependingOn);
|
||||
aggregateChange.addAction(insert);
|
||||
|
||||
referencedEntities(o).forEach(e -> saveReferencedEntities(e, aggregateChange, insert));
|
||||
referencedEntities(o).forEach(propertyAndValue -> saveReferencedEntities(propertyAndValue, aggregateChange, insert));
|
||||
} else {
|
||||
|
||||
deleteReferencedEntities(entityInformation.getRequiredId(o), aggregateChange);
|
||||
@@ -64,32 +68,35 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
|
||||
Update<Object> update = DbAction.update(o, dependingOn);
|
||||
aggregateChange.addAction(update);
|
||||
|
||||
referencedEntities(o).forEach(e -> insertReferencedEntities(e, aggregateChange, update));
|
||||
referencedEntities(o).forEach(propertyAndValue -> insertReferencedEntities(propertyAndValue, aggregateChange, update));
|
||||
}
|
||||
}
|
||||
|
||||
private void saveReferencedEntities(Object o, AggregateChange aggregateChange, DbAction dependingOn) {
|
||||
private void saveReferencedEntities(PropertyAndValue propertyAndValue, AggregateChange aggregateChange, DbAction dependingOn) {
|
||||
|
||||
saveActions(o, dependingOn).forEach(a -> {
|
||||
saveActions(propertyAndValue, dependingOn).forEach(a -> {
|
||||
|
||||
aggregateChange.addAction(a);
|
||||
referencedEntities(o).forEach(e -> saveReferencedEntities(e, aggregateChange, a));
|
||||
referencedEntities(propertyAndValue.value).forEach(pav -> saveReferencedEntities(pav, aggregateChange, a));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private <T> Stream<DbAction> saveActions(T t, DbAction dependingOn) {
|
||||
private Stream<DbAction> saveActions(PropertyAndValue propertyAndValue, DbAction dependingOn) {
|
||||
|
||||
if (Collection.class.isAssignableFrom(ClassUtils.getUserClass(t))) {
|
||||
return collectionSaveAction((Collection) t, dependingOn);
|
||||
if (Map.Entry.class.isAssignableFrom(ClassUtils.getUserClass(propertyAndValue.value))) {
|
||||
return mapEntrySaveAction(propertyAndValue, dependingOn);
|
||||
}
|
||||
|
||||
return Stream.of(singleSaveAction(t, dependingOn));
|
||||
return Stream.of(singleSaveAction(propertyAndValue.value, dependingOn));
|
||||
}
|
||||
|
||||
private Stream<DbAction> collectionSaveAction(Collection collection, DbAction dependingOn) {
|
||||
private Stream<DbAction> mapEntrySaveAction(PropertyAndValue propertyAndValue, DbAction dependingOn) {
|
||||
|
||||
return collection.stream().map(e -> singleSaveAction(e, dependingOn));
|
||||
Map.Entry<Object, Object> entry = (Map.Entry) propertyAndValue.value;
|
||||
|
||||
DbAction action = singleSaveAction(entry.getValue(), dependingOn);
|
||||
action.getAdditionalValues().put(propertyAndValue.property.getKeyColumn(), entry.getKey());
|
||||
return Stream.of(action);
|
||||
}
|
||||
|
||||
private <T> DbAction singleSaveAction(T t, DbAction dependingOn) {
|
||||
@@ -100,22 +107,36 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
|
||||
return entityInformation.isNew(t) ? DbAction.insert(t, dependingOn) : DbAction.update(t, dependingOn);
|
||||
}
|
||||
|
||||
private void insertReferencedEntities(Object o, AggregateChange aggregateChange, DbAction dependingOn) {
|
||||
private void insertReferencedEntities(PropertyAndValue propertyAndValue, AggregateChange aggregateChange, DbAction dependingOn) {
|
||||
|
||||
aggregateChange.addAction(DbAction.insert(o, dependingOn));
|
||||
referencedEntities(o).forEach(e -> insertReferencedEntities(e, aggregateChange, dependingOn));
|
||||
Insert<Object> insert;
|
||||
if (propertyAndValue.property.isMap()) {
|
||||
|
||||
Entry<Object, Object> valueAsEntry = (Entry<Object, Object>) propertyAndValue.value;
|
||||
insert = DbAction.insert(valueAsEntry.getValue(), dependingOn);
|
||||
insert.getAdditionalValues().put(propertyAndValue.property.getKeyColumn(), valueAsEntry.getKey());
|
||||
} else {
|
||||
insert = DbAction.insert(propertyAndValue.value, dependingOn);
|
||||
}
|
||||
|
||||
aggregateChange.addAction(insert);
|
||||
referencedEntities(insert.getEntity())
|
||||
.forEach(pav -> insertReferencedEntities(pav, aggregateChange, dependingOn));
|
||||
}
|
||||
|
||||
private Stream<Object> referencedEntities(Object o) {
|
||||
private Stream<PropertyAndValue> referencedEntities(Object o) {
|
||||
|
||||
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(o.getClass());
|
||||
|
||||
return StreamUtils.createStreamFromIterator(persistentEntity.iterator()) //
|
||||
.filter(PersistentProperty::isEntity)
|
||||
.flatMap(p -> referencedEntity(p, persistentEntity.getPropertyAccessor(o)));
|
||||
.filter(PersistentProperty::isEntity) //
|
||||
.flatMap( //
|
||||
p -> referencedEntity(p, persistentEntity.getPropertyAccessor(o)) //
|
||||
.map(e -> new PropertyAndValue(p, e)) //
|
||||
);
|
||||
}
|
||||
|
||||
private Stream<?> referencedEntity(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {
|
||||
private Stream<Object> referencedEntity(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {
|
||||
|
||||
Class<?> actualType = p.getActualType();
|
||||
JdbcPersistentEntity<?> persistentEntity = context //
|
||||
@@ -127,9 +148,15 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
|
||||
|
||||
Class<?> type = p.getType();
|
||||
|
||||
return Collection.class.isAssignableFrom(type) //
|
||||
? collectionPropertyAsStream(p, propertyAccessor) //
|
||||
: singlePropertyAsStream(p, propertyAccessor);
|
||||
if (Collection.class.isAssignableFrom(type)) {
|
||||
return collectionPropertyAsStream(p, propertyAccessor);
|
||||
}
|
||||
|
||||
if (Map.class.isAssignableFrom(type)) {
|
||||
return mapPropertyAsStream(p, propertyAccessor);
|
||||
}
|
||||
|
||||
return singlePropertyAsStream(p, propertyAccessor);
|
||||
}
|
||||
|
||||
private Stream<Object> collectionPropertyAsStream(JdbcPersistentProperty p,
|
||||
@@ -142,6 +169,15 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
|
||||
: ((Collection<Object>) property).stream();
|
||||
}
|
||||
|
||||
private Stream<Object> mapPropertyAsStream(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {
|
||||
|
||||
Object property = propertyAccessor.getProperty(p);
|
||||
|
||||
return property == null //
|
||||
? Stream.empty() //
|
||||
: ((Map<Object, Object>) property).entrySet().stream().map(e -> (Object) e);
|
||||
}
|
||||
|
||||
private Stream<Object> singlePropertyAsStream(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {
|
||||
|
||||
Object property = propertyAccessor.getProperty(p);
|
||||
@@ -151,4 +187,11 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
|
||||
|
||||
return Stream.of(property);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class PropertyAndValue {
|
||||
|
||||
private final JdbcPersistentProperty property;
|
||||
private final Object value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class BasicJdbcPersistentProperty extends AnnotationBasedPersistentProper
|
||||
* @see org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty#getColumnName()
|
||||
*/
|
||||
public String getColumnName() {
|
||||
return this.context.getNamingStrategy().getColumnName(this);
|
||||
return context.getNamingStrategy().getColumnName(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +104,12 @@ public class BasicJdbcPersistentProperty extends AnnotationBasedPersistentProper
|
||||
|
||||
@Override
|
||||
public String getReverseColumnName() {
|
||||
return getOwner().getTableName();
|
||||
return context.getNamingStrategy().getReverseColumnName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyColumn() {
|
||||
return isMap() ? context.getNamingStrategy().getKeyColumn(this) : null;
|
||||
}
|
||||
|
||||
private Class columnTypeIfEntity(Class type) {
|
||||
|
||||
@@ -50,4 +50,14 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
public String getColumnName(JdbcPersistentProperty property) {
|
||||
return property.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReverseColumnName(JdbcPersistentProperty property) {
|
||||
return property.getOwner().getTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyColumn(JdbcPersistentProperty property) {
|
||||
return getReverseColumnName(property) + "_key";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,4 +44,6 @@ public interface JdbcPersistentProperty extends PersistentProperty<JdbcPersisten
|
||||
JdbcPersistentEntity<?> getOwner();
|
||||
|
||||
String getReverseColumnName();
|
||||
|
||||
String getKeyColumn();
|
||||
}
|
||||
|
||||
@@ -30,4 +30,17 @@ public interface NamingStrategy {
|
||||
return this.getSchema() + (this.getSchema().equals("") ? "" : ".") + this.getTableName(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a reference A -> B this is the name in the table for B which references A.
|
||||
*
|
||||
* @return a column name.
|
||||
*/
|
||||
String getReverseColumnName(JdbcPersistentProperty property);
|
||||
|
||||
/**
|
||||
* For a map valued reference A -> Map>X,B< this is the name of the column in the tabel for B holding the key of the map.
|
||||
* @return
|
||||
*/
|
||||
String getKeyColumn(JdbcPersistentProperty property);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user