DATAJDBC-223 - Chains of Lists or Maps get properly stored and loaded.
Also solved DATAJDBC-369 since it made refactoring easier. Known limitation: Back-references to intermediate key columns currently can't get renamed and use the name defined by the property where they become part of the path. Backward compatibility of the JdbcConfiguration is still broken. Original pull request: #153.
This commit is contained in:
committed by
Mark Paluch
parent
c87d8b8d31
commit
097190ee42
@@ -28,6 +28,6 @@ public class EntityRowMapper<T> extends org.springframework.data.jdbc.core.conve
|
||||
|
||||
public EntityRowMapper(RelationalPersistentEntity<T> entity, JdbcConverter converter,
|
||||
DataAccessStrategy accessStrategy) {
|
||||
super(entity, converter, accessStrategy);
|
||||
super(entity, converter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -54,18 +52,6 @@ public class JdbcIdentifierBuilder {
|
||||
return new JdbcIdentifierBuilder(identifier);
|
||||
}
|
||||
|
||||
private static RelationalPersistentProperty getLastIdProperty(
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
|
||||
RelationalPersistentProperty idProperty = path.getRequiredLeafProperty().getOwner().getIdProperty();
|
||||
|
||||
if (idProperty != null) {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
return getLastIdProperty(path.getParentPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a qualifier to the identifier to build. A qualifier is a map key or a list index.
|
||||
*
|
||||
@@ -78,7 +64,7 @@ public class JdbcIdentifierBuilder {
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(value, "Value must not be null");
|
||||
|
||||
identifier = identifier.withPart(path.getKeyColumn(), value, path.getQualifierColumnType());
|
||||
identifier = identifier.withPart(path.getQualifierColumn(), value, path.getQualifierColumnType());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.jdbc.support.JdbcUtil;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
@@ -39,6 +40,7 @@ import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -53,6 +55,7 @@ import org.springframework.util.Assert;
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Christoph Strobl
|
||||
* @since 1.1
|
||||
* @see MappingContext
|
||||
* @see SimpleTypeHolder
|
||||
* @see CustomConversions
|
||||
@@ -61,70 +64,51 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BasicJdbcConverter.class);
|
||||
private static final Converter<Iterable<?>, Map<?, ?>> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter();
|
||||
|
||||
private final JdbcTypeFactory typeFactory;
|
||||
|
||||
private RelationResolver relationResolver;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a
|
||||
* {@link JdbcTypeFactory#unsupported() no-op type factory} throwing {@link UnsupportedOperationException} on type
|
||||
* creation. Use {@link #BasicJdbcConverter(MappingContext, JdbcTypeFactory)} to convert arrays and large objects into
|
||||
* JDBC-specific types.
|
||||
* creation. Use {@link #BasicJdbcConverter(MappingContext, RelationResolver, JdbcTypeFactory)} to convert arrays and
|
||||
* large objects into JDBC-specific types.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context) {
|
||||
this(context, JdbcTypeFactory.unsupported());
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
RelationResolver relationResolver) {
|
||||
|
||||
super(context);
|
||||
|
||||
Assert.notNull(relationResolver, "RelationResolver must not be null");
|
||||
|
||||
this.relationResolver = relationResolver;
|
||||
this.typeFactory = JdbcTypeFactory.unsupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
|
||||
* @param typeFactory must not be {@literal null}
|
||||
* @since 1.1
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
JdbcTypeFactory typeFactory) {
|
||||
|
||||
super(context);
|
||||
|
||||
Assert.notNull(typeFactory, "JdbcTypeFactory must not be null");
|
||||
|
||||
this.typeFactory = typeFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext}, {@link CustomConversions}, and
|
||||
* {@link JdbcTypeFactory}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param conversions must not be {@literal null}.
|
||||
* @param typeFactory must not be {@literal null}
|
||||
* @since 1.1
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
CustomConversions conversions, JdbcTypeFactory typeFactory) {
|
||||
RelationResolver relationResolver, CustomConversions conversions, JdbcTypeFactory typeFactory) {
|
||||
|
||||
super(context, conversions);
|
||||
|
||||
Assert.notNull(typeFactory, "JdbcTypeFactory must not be null");
|
||||
this.typeFactory = typeFactory;
|
||||
}
|
||||
Assert.notNull(relationResolver, "RelationResolver must not be null");
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and {@link CustomConversions}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param conversions must not be {@literal null}.
|
||||
* @deprecated use one of the constructors with {@link JdbcTypeFactory} parameter.
|
||||
*/
|
||||
@Deprecated
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
CustomConversions conversions) {
|
||||
this(context, conversions, JdbcTypeFactory.unsupported());
|
||||
this.relationResolver = relationResolver;
|
||||
this.typeFactory = typeFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,9 +129,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
if (AggregateReference.class.isAssignableFrom(type.getType())) {
|
||||
|
||||
TypeInformation<?> idType = type.getSuperTypeInformation(AggregateReference.class).getTypeArguments().get(1);
|
||||
|
||||
return AggregateReference.to(readValue(value, idType));
|
||||
return readAggregateReference(value, type);
|
||||
}
|
||||
|
||||
if (value instanceof Array) {
|
||||
@@ -161,6 +143,14 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
return super.readValue(value, type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private Object readAggregateReference(@Nullable Object value, TypeInformation<?> type) {
|
||||
|
||||
TypeInformation<?> idType = type.getSuperTypeInformation(AggregateReference.class).getTypeArguments().get(1);
|
||||
|
||||
return AggregateReference.to(readValue(value, idType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.relational.core.conversion.RelationalConverter#writeValue(java.lang.Object, org.springframework.data.util.TypeInformation)
|
||||
@@ -246,47 +236,63 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T mapRow(RelationalPersistentEntity<T> entity, DataAccessStrategy accessStrategy, ResultSet resultSet) {
|
||||
return new ReadingContext<T>(entity, accessStrategy, resultSet).mapRow();
|
||||
public <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key) {
|
||||
return new ReadingContext<T>(
|
||||
new PersistentPropertyPathExtension(
|
||||
(MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty>) getMappingContext(), entity),
|
||||
resultSet, Identifier.empty(), key).mapRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key) {
|
||||
return new ReadingContext<T>(path, resultSet, identifier, key).mapRow();
|
||||
}
|
||||
|
||||
private class ReadingContext<T> {
|
||||
|
||||
private final RelationalPersistentEntity<T> entity;
|
||||
private final RelationalPersistentProperty idProperty;
|
||||
|
||||
private final ResultSet resultSet;
|
||||
PersistentPropertyPathExtension path;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
private final PersistentPropertyPathExtension rootPath;
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final Identifier identifier;
|
||||
private final Object key;
|
||||
|
||||
ReadingContext(RelationalPersistentEntity<T> entity, DataAccessStrategy accessStrategy, ResultSet resultSet) {
|
||||
@SuppressWarnings("unchecked")
|
||||
private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSet resultSet, Identifier identifier,
|
||||
Object key) {
|
||||
|
||||
|
||||
RelationalPersistentEntity<T> entity = (RelationalPersistentEntity<T>) rootPath.getLeafEntity();
|
||||
|
||||
Assert.notNull(entity, "The rootPath must point to an entity.");
|
||||
|
||||
this.entity = entity;
|
||||
this.idProperty = entity.getIdProperty();
|
||||
this.accessStrategy = accessStrategy;
|
||||
this.resultSet = resultSet;
|
||||
this.rootPath = rootPath;
|
||||
this.path = new PersistentPropertyPathExtension(
|
||||
(MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty>) getMappingContext(), entity);
|
||||
(MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty>) getMappingContext(), this.entity);
|
||||
this.identifier = identifier;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public ReadingContext(RelationalPersistentEntity<T> entity, DataAccessStrategy accessStrategy, ResultSet resultSet,
|
||||
PersistentPropertyPathExtension path) {
|
||||
private ReadingContext(RelationalPersistentEntity<T> entity, ResultSet resultSet,
|
||||
PersistentPropertyPathExtension rootPath, PersistentPropertyPathExtension path, Identifier identifier,
|
||||
Object key) {
|
||||
|
||||
this.entity = entity;
|
||||
this.idProperty = entity.getIdProperty();
|
||||
this.accessStrategy = accessStrategy;
|
||||
this.resultSet = resultSet;
|
||||
this.rootPath = rootPath;
|
||||
this.path = path;
|
||||
this.identifier = identifier;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
private ReadingContext<?> extendBy(RelationalPersistentProperty property) {
|
||||
return new ReadingContext(getMappingContext().getRequiredPersistentEntity(property.getActualType()),
|
||||
accessStrategy, resultSet, path.extendBy(property));
|
||||
private <S> ReadingContext<S> extendBy(RelationalPersistentProperty property) {
|
||||
return new ReadingContext<S>((RelationalPersistentEntity<S>) getMappingContext().getRequiredPersistentEntity(property.getActualType()), resultSet,
|
||||
rootPath.extendBy(property), path.extendBy(property), identifier, key);
|
||||
}
|
||||
|
||||
T mapRow() {
|
||||
@@ -319,10 +325,14 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
@Nullable
|
||||
private Object readOrLoadProperty(@Nullable Object id, RelationalPersistentProperty property) {
|
||||
|
||||
if (property.isCollectionLike() && property.isEntity() && id != null) {
|
||||
return accessStrategy.findAllByProperty(id, property);
|
||||
} else if (property.isMap() && id != null) {
|
||||
return ITERABLE_OF_ENTRY_TO_MAP_CONVERTER.convert(accessStrategy.findAllByProperty(id, property));
|
||||
if ((property.isCollectionLike() && property.isEntity()) || property.isMap()) {
|
||||
|
||||
Iterable<Object> allByPath = resolveRelation(id, property);
|
||||
|
||||
return property.isMap() //
|
||||
? ITERABLE_OF_ENTRY_TO_MAP_CONVERTER.convert(allByPath) //
|
||||
: allByPath;
|
||||
|
||||
} else if (property.isEmbedded()) {
|
||||
return readEmbeddedEntityFrom(id, property);
|
||||
} else {
|
||||
@@ -330,6 +340,18 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
}
|
||||
}
|
||||
|
||||
private Iterable<Object> resolveRelation(@Nullable Object id, RelationalPersistentProperty property) {
|
||||
|
||||
Identifier identifier = id == null //
|
||||
? this.identifier.withPart(rootPath.getQualifierColumn(), key, Object.class) //
|
||||
: Identifier.of(rootPath.extendBy(property).getReverseColumnName(), id, Object.class);
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> propertyPath = path.extendBy(property)
|
||||
.getRequiredPersistentPropertyPath();
|
||||
|
||||
return relationResolver.findAllByPath(identifier, propertyPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single value or a complete Entity from the {@link ResultSet} passed as an argument.
|
||||
*
|
||||
@@ -355,10 +377,12 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
return newContext.hasInstanceValues(idValue) ? newContext.createInstanceInternal(idValue) : null;
|
||||
}
|
||||
|
||||
private boolean hasInstanceValues(Object idValue) {
|
||||
private boolean hasInstanceValues(@Nullable Object idValue) {
|
||||
|
||||
RelationalPersistentEntity<?> persistentEntity = path.getLeafEntity();
|
||||
|
||||
Assert.state(persistentEntity != null, "Entity must not be null");
|
||||
|
||||
for (RelationalPersistentProperty embeddedProperty : persistentEntity) {
|
||||
|
||||
// if the embedded contains Lists, Sets or Maps we consider it non-empty
|
||||
@@ -375,11 +399,11 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <S> S readEntityFrom(RelationalPersistentProperty property, PersistentPropertyPathExtension path) {
|
||||
private Object readEntityFrom(RelationalPersistentProperty property, PersistentPropertyPathExtension path) {
|
||||
|
||||
ReadingContext<S> newContext = (ReadingContext<S>) extendBy(property);
|
||||
ReadingContext<?> newContext = extendBy(property);
|
||||
|
||||
RelationalPersistentEntity<S> entity = (RelationalPersistentEntity<S>) getMappingContext()
|
||||
RelationalPersistentEntity<?> entity = getMappingContext()
|
||||
.getRequiredPersistentEntity(property.getActualType());
|
||||
|
||||
RelationalPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
@@ -140,6 +140,15 @@ public class CascadingDataAccessStrategy implements DataAccessStrategy {
|
||||
return collect(das -> das.findAllById(ids, domainType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.RelationResolver#findAllByPath(org.springframework.data.relational.domain.Identifier, org.springframework.data.mapping.PersistentPropertyPath)
|
||||
*/
|
||||
@Override
|
||||
public <T> Iterable<T> findAllByPath(Identifier identifier, PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
return collect(das -> das.findAllByPath(identifier, path));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllByProperty(java.lang.Object, org.springframework.data.relational.core.mapping.RelationalPersistentProperty)
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public interface DataAccessStrategy {
|
||||
public interface DataAccessStrategy extends RelationResolver {
|
||||
|
||||
/**
|
||||
* Inserts a the data of a single entity. Referenced entities don't get handled.
|
||||
@@ -144,12 +144,26 @@ public interface DataAccessStrategy {
|
||||
*/
|
||||
<T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.RelationResolver#findAllByPath(org.springframework.data.relational.domain.Identifier, org.springframework.data.mapping.PersistentPropertyPath)
|
||||
*/
|
||||
@Override
|
||||
default <T> Iterable<T> findAllByPath(Identifier identifier,
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
|
||||
Object rootId = identifier.toMap().get(path.getRequiredLeafProperty().getReverseColumnName());
|
||||
return findAllByProperty(rootId, path.getRequiredLeafProperty());
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds all entities reachable via {@literal property} from the instance identified by {@literal rootId}.
|
||||
*
|
||||
* @param rootId Id of the root object on which the {@literal propertyPath} is based.
|
||||
* @param property Leading from the root object to the entities to be found.
|
||||
* @deprecated Use #findAllByPath instead.
|
||||
*/
|
||||
@Deprecated
|
||||
<T> Iterable<T> findAllByProperty(Object rootId, RelationalPersistentProperty property);
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -63,21 +64,6 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
private final @NonNull RelationalMappingContext context;
|
||||
private final @NonNull JdbcConverter converter;
|
||||
private final @NonNull NamedParameterJdbcOperations operations;
|
||||
private final @NonNull DataAccessStrategy accessStrategy;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param sqlGeneratorSource must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
*/
|
||||
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context,
|
||||
JdbcConverter converter, NamedParameterJdbcOperations operations) {
|
||||
this(sqlGeneratorSource, context, converter, operations, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultDataAccessStrategy}
|
||||
@@ -86,12 +72,10 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
* @param context must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
* @param mappingAccessStrategy can be {@literal null}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context,
|
||||
JdbcConverter converter, NamedParameterJdbcOperations operations,
|
||||
@Nullable DataAccessStrategy mappingAccessStrategy) {
|
||||
JdbcConverter converter, NamedParameterJdbcOperations operations) {
|
||||
|
||||
Assert.notNull(sqlGeneratorSource, "SqlGeneratorSource must not be null");
|
||||
Assert.notNull(context, "RelationalMappingContext must not be null");
|
||||
@@ -102,7 +86,6 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
this.context = context;
|
||||
this.converter = converter;
|
||||
this.operations = operations;
|
||||
this.accessStrategy = mappingAccessStrategy == null ? this : mappingAccessStrategy;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -236,7 +219,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
MapSqlParameterSource parameter = createIdParameterSource(id, domainType);
|
||||
|
||||
try {
|
||||
return operations.queryForObject(findOneSql, parameter, (RowMapper<T>) getEntityRowMapper(domainType));
|
||||
return operations.queryForObject(findOneSql, parameter,
|
||||
(RowMapper<T>) getEntityRowMapper(domainType));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
@@ -249,7 +233,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> Iterable<T> findAll(Class<T> domainType) {
|
||||
return operations.query(sql(domainType).getFindAll(), (RowMapper<T>) getEntityRowMapper(domainType));
|
||||
return operations.query(sql(domainType).getFindAll(),
|
||||
(RowMapper<T>) getEntityRowMapper(domainType));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -267,7 +252,39 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
String findAllInListSql = sql(domainType).getFindAllInList();
|
||||
|
||||
return operations.query(findAllInListSql, parameterSource, (RowMapper<T>) getEntityRowMapper(domainType));
|
||||
return operations.query(findAllInListSql, parameterSource,
|
||||
(RowMapper<T>) getEntityRowMapper(domainType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.RelationResolver#findAllByPath(org.springframework.data.relational.domain.Identifier, org.springframework.data.mapping.PersistentPropertyPath)
|
||||
*/
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> Iterable<T> findAllByPath(Identifier identifier,
|
||||
PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
|
||||
|
||||
Assert.notNull(identifier, "identifier must not be null.");
|
||||
Assert.notNull(propertyPath, "propertyPath must not be null.");
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, propertyPath);
|
||||
|
||||
Class<?> actualType = path.getActualType();
|
||||
String findAllByProperty = sql(actualType) //
|
||||
.getFindAllByProperty(identifier, path.getQualifierColumn(), path.isOrdered());
|
||||
|
||||
MapSqlParameterSource parameters = new MapSqlParameterSource();
|
||||
|
||||
identifier.forEach((name, value, targetType) -> {
|
||||
parameters.addValue(name, value);
|
||||
});
|
||||
|
||||
return operations.query(findAllByProperty, parameters, //
|
||||
(RowMapper<T>) (path.isMap() //
|
||||
? this.getMapEntityRowMapper(path, identifier) //
|
||||
: this.getEntityRowMapper(path, identifier)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -280,16 +297,9 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
Assert.notNull(rootId, "rootId must not be null.");
|
||||
|
||||
Class<?> actualType = property.getActualType();
|
||||
String findAllByProperty = sql(actualType) //
|
||||
.getFindAllByProperty(property.getReverseColumnName(), property.getKeyColumn(), property.isOrdered());
|
||||
|
||||
MapSqlParameterSource parameter = new MapSqlParameterSource(property.getReverseColumnName(), rootId);
|
||||
|
||||
return operations.query(findAllByProperty, parameter, //
|
||||
(RowMapper<T>) (property.isMap() //
|
||||
? this.getMapEntityRowMapper(property) //
|
||||
: this.getEntityRowMapper(actualType)));
|
||||
Class<?> rootType = property.getOwner().getType();
|
||||
return findAllByPath(Identifier.of(property.getReverseColumnName(), rootId, rootType),
|
||||
context.getPersistentPropertyPath(property.getName(), rootType));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -385,15 +395,19 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
}
|
||||
|
||||
private EntityRowMapper<?> getEntityRowMapper(Class<?> domainType) {
|
||||
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), converter, accessStrategy);
|
||||
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), converter);
|
||||
}
|
||||
|
||||
private RowMapper<?> getMapEntityRowMapper(RelationalPersistentProperty property) {
|
||||
private EntityRowMapper<?> getEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
|
||||
return new EntityRowMapper<>(path, converter, identifier);
|
||||
}
|
||||
|
||||
String keyColumn = property.getKeyColumn();
|
||||
Assert.notNull(keyColumn, () -> "KeyColumn must not be null for " + property);
|
||||
private RowMapper<?> getMapEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
|
||||
|
||||
return new MapEntityRowMapper<>(getEntityRowMapper(property.getActualType()), keyColumn);
|
||||
String keyColumn = path.getQualifierColumn();
|
||||
Assert.notNull(keyColumn, () -> "KeyColumn must not be null for " + path);
|
||||
|
||||
return new MapEntityRowMapper<>(path, converter, identifier, keyColumn);
|
||||
}
|
||||
|
||||
private <T> MapSqlParameterSource createIdParameterSource(Object id, Class<T> domainType) {
|
||||
|
||||
@@ -135,6 +135,15 @@ public class DelegatingDataAccessStrategy implements DataAccessStrategy {
|
||||
return delegate.findAllById(ids, domainType);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.RelationResolver#findAllByPath(org.springframework.data.relational.domain.Identifier, org.springframework.data.mapping.PersistentPropertyPath)
|
||||
*/
|
||||
@Override
|
||||
public <T> Iterable<T> findAllByPath(Identifier identifier, PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
return delegate.findAllByPath(identifier, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllByProperty(java.lang.Object, org.springframework.data.relational.core.mapping.RelationalPersistentProperty)
|
||||
|
||||
@@ -17,7 +17,9 @@ package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
@@ -34,16 +36,24 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
private final RelationalPersistentEntity<T> entity;
|
||||
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final JdbcConverter converter;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
private final Identifier identifier;
|
||||
|
||||
public EntityRowMapper(RelationalPersistentEntity<T> entity, JdbcConverter converter,
|
||||
DataAccessStrategy accessStrategy) {
|
||||
public EntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier) {
|
||||
|
||||
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public EntityRowMapper(RelationalPersistentEntity<T> entity, JdbcConverter converter) {
|
||||
|
||||
this.entity = entity;
|
||||
this.path = null;
|
||||
this.converter = converter;
|
||||
this.accessStrategy = accessStrategy;
|
||||
this.identifier = null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -52,7 +62,9 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
*/
|
||||
@Override
|
||||
public T mapRow(ResultSet resultSet, int rowNumber) {
|
||||
return converter.mapRow(entity, accessStrategy, resultSet);
|
||||
|
||||
return path == null ? converter.mapRow(entity, resultSet, rowNumber)
|
||||
: converter.mapRow(path, resultSet, identifier, rowNumber);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.springframework.data.jdbc.core.convert;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -42,9 +44,7 @@ public interface JdbcConverter extends RelationalConverter {
|
||||
*/
|
||||
JdbcValue writeJdbcValue(@Nullable Object value, Class<?> type, int sqlType);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int)
|
||||
*/
|
||||
<T> T mapRow(RelationalPersistentEntity<T> entity, DataAccessStrategy accessStrategy, ResultSet resultSet);
|
||||
<T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key);
|
||||
|
||||
<T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
@@ -32,22 +34,35 @@ import org.springframework.lang.NonNull;
|
||||
*/
|
||||
class MapEntityRowMapper<T> implements RowMapper<Map.Entry<Object, T>> {
|
||||
|
||||
private final RowMapper<T> delegate;
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final JdbcConverter converter;
|
||||
private final Identifier identifier;
|
||||
|
||||
private final String keyColumn;
|
||||
|
||||
/**
|
||||
* @param delegate rowmapper used as a delegate for obtaining the map values.
|
||||
* @param path
|
||||
* @param converter
|
||||
* @param identifier
|
||||
* @param keyColumn the name of the key column.
|
||||
*/
|
||||
MapEntityRowMapper(RowMapper<T> delegate, String keyColumn) {
|
||||
MapEntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter,
|
||||
Identifier identifier, String keyColumn) {
|
||||
|
||||
this.delegate = delegate;
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
this.identifier = identifier;
|
||||
this.keyColumn = keyColumn;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Map.Entry<Object, T> mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return new HashMap.SimpleEntry<>(rs.getObject(keyColumn), delegate.mapRow(rs, rowNum));
|
||||
Object key = rs.getObject(keyColumn);
|
||||
return new HashMap.SimpleEntry<>(key, mapEntity(rs, key));
|
||||
}
|
||||
|
||||
private T mapEntity(ResultSet resultSet, Object key) {
|
||||
return converter.mapRow(path, resultSet, identifier, key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
|
||||
/**
|
||||
* Resolves relations within an aggregate.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface RelationResolver {
|
||||
|
||||
/**
|
||||
* Finds all entities reachable via {@literal path}.
|
||||
*
|
||||
* @param identifier the combination of Id, map keys and list indexes that identify the parent of the entity to be loaded. Must not be {@literal null}.
|
||||
* @param path the path from the aggregate root to the entities to be resolved. Must not be {@literal null}.
|
||||
* @param <T> the type of entity created by this class
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
<T> Iterable<T> findAllByPath(Identifier identifier,
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path);
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEnti
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.*;
|
||||
import org.springframework.data.relational.core.sql.render.SqlRenderer;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -163,34 +164,51 @@ class SqlGenerator {
|
||||
* {@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 parentIdentifier 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.
|
||||
* @param ordered whether the SQL statement should include an ORDER BY for the keyColumn. If this is {@code true}, the
|
||||
* keyColumn must not be {@code null}.
|
||||
* @return a SQL String.
|
||||
*/
|
||||
String getFindAllByProperty(String columnName, @Nullable String keyColumn, boolean ordered) {
|
||||
String getFindAllByProperty(Identifier parentIdentifier, @Nullable String keyColumn, boolean ordered) {
|
||||
|
||||
Assert.isTrue(keyColumn != null || !ordered,
|
||||
"If the SQL statement should be ordered a keyColumn to order by must be provided.");
|
||||
|
||||
SelectBuilder.SelectWhere builder = selectBuilder(
|
||||
keyColumn == null ? Collections.emptyList() : Collections.singleton(keyColumn));
|
||||
SelectBuilder.SelectWhere builder = selectBuilder( //
|
||||
keyColumn == null //
|
||||
? Collections.emptyList() //
|
||||
: Collections.singleton(keyColumn) //
|
||||
);
|
||||
|
||||
Table table = getTable();
|
||||
SelectBuilder.SelectWhereAndOr withWhereClause = builder
|
||||
.where(table.column(columnName).isEqualTo(getBindMarker(columnName)));
|
||||
|
||||
Select select;
|
||||
if (ordered) {
|
||||
select = withWhereClause.orderBy(table.column(keyColumn).as(keyColumn)).build();
|
||||
} else {
|
||||
select = withWhereClause.build();
|
||||
}
|
||||
Condition condition = buildConditionForBackReference(parentIdentifier, table);
|
||||
|
||||
SelectBuilder.SelectWhereAndOr withWhereClause = builder.where(condition);
|
||||
|
||||
Select select = ordered //
|
||||
? withWhereClause.orderBy(table.column(keyColumn).as(keyColumn)).build() //
|
||||
: withWhereClause.build();
|
||||
|
||||
return render(select);
|
||||
}
|
||||
|
||||
private Condition buildConditionForBackReference(Identifier parentIdentifier, Table table) {
|
||||
|
||||
Condition condition = null;
|
||||
for (String backReferenceColumn : parentIdentifier.toMap().keySet()) {
|
||||
|
||||
Condition newCondition = table.column(backReferenceColumn).isEqualTo(getBindMarker(backReferenceColumn));
|
||||
|
||||
condition = condition == null ? newCondition : condition.and(newCondition);
|
||||
}
|
||||
|
||||
Assert.state(condition != null, "We need at least one condition");
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code SELECT COUNT(id) FROM … WHERE :id = …} statement.
|
||||
*
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.Map;
|
||||
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
|
||||
import org.springframework.data.jdbc.core.convert.CascadingDataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy;
|
||||
@@ -88,8 +87,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
sqlGeneratorSource, //
|
||||
context, //
|
||||
converter, //
|
||||
operations, //
|
||||
cascadingDataAccessStrategy //
|
||||
operations //
|
||||
);
|
||||
|
||||
delegatingDataAccessStrategy.setDelegate(defaultDataAccessStrategy);
|
||||
@@ -244,6 +242,13 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
new MyBatisContext(ids, null, domainType, Collections.emptyMap()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> findAllByPath(Identifier identifier,
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
return sqlSession().selectList(namespace(path.getBaseProperty().getOwner().getType()) + ".findAllByPath",
|
||||
new MyBatisContext(identifier, null, path.getLeafProperty().getType(), Collections.emptyMap()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllByProperty(java.lang.Object, org.springframework.data.relational.core.mapping.RelationalPersistentProperty)
|
||||
|
||||
@@ -20,7 +20,9 @@ import java.util.Optional;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
|
||||
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
@@ -28,6 +30,7 @@ import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.RelationResolver;
|
||||
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
@@ -73,8 +76,11 @@ public abstract class AbstractJdbcConfiguration {
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
@Bean
|
||||
public JdbcConverter jdbcConverter(RelationalMappingContext mappingContext, JdbcOperations operations) {
|
||||
return new BasicJdbcConverter(mappingContext, jdbcCustomConversions(), new DefaultJdbcTypeFactory(operations));
|
||||
public JdbcConverter jdbcConverter(RelationalMappingContext mappingContext, NamedParameterJdbcOperations operations,
|
||||
@Lazy RelationResolver relationResolver) {
|
||||
|
||||
return new BasicJdbcConverter(mappingContext, relationResolver, jdbcCustomConversions(),
|
||||
new DefaultJdbcTypeFactory(operations.getJdbcOperations()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,16 +103,30 @@ public abstract class AbstractJdbcConfiguration {
|
||||
* @param publisher for publishing events. Must not be {@literal null}.
|
||||
* @param context the mapping context to be used. Must not be {@literal null}.
|
||||
* @param converter the conversions used when reading and writing from/to the database. Must not be {@literal null}.
|
||||
* @param operations {@link NamedParameterJdbcOperations} used for accessing the database. Must not be
|
||||
* {@literal null}.
|
||||
* @return a {@link JdbcAggregateTemplate}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Bean
|
||||
public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationEventPublisher publisher,
|
||||
RelationalMappingContext context, JdbcConverter converter, NamedParameterJdbcOperations operations) {
|
||||
RelationalMappingContext context, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
|
||||
|
||||
DataAccessStrategy dataAccessStrategy = new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context,
|
||||
converter, operations);
|
||||
return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link DataAccessStrategy} as a bean for reuse in the {@link JdbcAggregateOperations} and the
|
||||
* {@link RelationalConverter}.
|
||||
*
|
||||
* @param operations
|
||||
* @param namingStrategy
|
||||
* @param jdbcConverter
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public DataAccessStrategy dataAccessStrategy(NamedParameterJdbcOperations operations,
|
||||
Optional<NamingStrategy> namingStrategy, JdbcConverter jdbcConverter) {
|
||||
|
||||
JdbcMappingContext context = jdbcMappingContext(namingStrategy);
|
||||
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, jdbcConverter, operations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Optional;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcTypeFactory;
|
||||
import org.springframework.data.jdbc.core.convert.RelationResolver;
|
||||
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
@@ -74,9 +76,9 @@ public class JdbcConfiguration {
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
@Bean
|
||||
public RelationalConverter relationalConverter(RelationalMappingContext mappingContext) {
|
||||
public RelationalConverter relationalConverter(RelationalMappingContext mappingContext, @Lazy RelationResolver relationalResolver) {
|
||||
|
||||
return new BasicJdbcConverter(mappingContext, jdbcCustomConversions(), JdbcTypeFactory.unsupported());
|
||||
return new BasicJdbcConverter(mappingContext, relationalResolver, jdbcCustomConversions(), JdbcTypeFactory.unsupported());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,8 +106,23 @@ public class JdbcConfiguration {
|
||||
@Bean
|
||||
public JdbcAggregateOperations jdbcAggregateOperations(ApplicationEventPublisher publisher,
|
||||
RelationalMappingContext context, JdbcConverter converter, NamedParameterJdbcOperations operations) {
|
||||
DataAccessStrategy dataAccessStrategy = new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context,
|
||||
converter, operations);
|
||||
return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy);
|
||||
return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy(context, converter, operations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link DataAccessStrategy} as a bean for reuse in the {@link JdbcAggregateOperations} and the
|
||||
* {@link RelationalConverter}.
|
||||
*
|
||||
* @param context
|
||||
* @param converter
|
||||
* @param operations
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public DataAccessStrategy dataAccessStrategy(RelationalMappingContext context, JdbcConverter converter,
|
||||
NamedParameterJdbcOperations operations) {
|
||||
|
||||
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context),
|
||||
context, converter, operations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +118,8 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
EntityRowMapper<?> defaultEntityRowMapper = new EntityRowMapper<>( //
|
||||
context.getRequiredPersistentEntity(domainType), //
|
||||
//
|
||||
converter, //
|
||||
accessStrategy);
|
||||
converter //
|
||||
);
|
||||
|
||||
return defaultEntityRowMapper;
|
||||
}
|
||||
|
||||
@@ -18,17 +18,22 @@ package org.springframework.data.jdbc.core;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.jdbc.core.PropertyPathTestingUtils.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Insert;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.InsertRoot;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultJdbcInterpreter}
|
||||
*
|
||||
@@ -48,9 +53,9 @@ public class DefaultJdbcInterpreterUnitTests {
|
||||
Element element = new Element();
|
||||
|
||||
InsertRoot<Container> containerInsert = new InsertRoot<>(container);
|
||||
Insert<?> elementInsert = new Insert<>(element, PropertyPathTestingUtils.toPath("element", Container.class, context),
|
||||
Insert<?> elementInsert = new Insert<>(element, toPath("element", Container.class, context),
|
||||
containerInsert);
|
||||
Insert<?> element1Insert = new Insert<>(element, PropertyPathTestingUtils.toPath("element.element1", Container.class, context),
|
||||
Insert<?> element1Insert = new Insert<>(element, toPath("element.element1", Container.class, context),
|
||||
elementInsert);
|
||||
|
||||
@Test // DATAJDBC-145
|
||||
@@ -114,6 +119,41 @@ public class DefaultJdbcInterpreterUnitTests {
|
||||
.containsExactly(tuple(BACK_REFERENCE, CONTAINER_ID, Long.class));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-223
|
||||
public void generateCascadingIds() {
|
||||
|
||||
|
||||
ListListContainer listListContainer = new ListListContainer();
|
||||
ListContainer listContainer = new ListContainer();
|
||||
|
||||
InsertRoot<ListListContainer> listListContainerInsert = new InsertRoot<>(listListContainer);
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> listContainersPath = toPath("listContainers", ListListContainer.class, context);
|
||||
Insert<?> listContainerInsert = new Insert<>(listContainer, listContainersPath, listListContainerInsert);
|
||||
listContainerInsert.getQualifiers().put(listContainersPath, 3);
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> listContainersElementsPath = toPath("listContainers.elements", ListListContainer.class, context);
|
||||
Insert<?> elementInsertInList = new Insert<>(element, listContainersElementsPath, listContainerInsert);
|
||||
elementInsertInList.getQualifiers().put(listContainersElementsPath, 6);
|
||||
elementInsertInList.getQualifiers().put(listContainersPath, 3);
|
||||
|
||||
|
||||
listListContainerInsert.setGeneratedId(CONTAINER_ID);
|
||||
|
||||
interpreter.interpret(elementInsertInList);
|
||||
|
||||
ArgumentCaptor<Identifier> argumentCaptor = ArgumentCaptor.forClass(Identifier.class);
|
||||
verify(dataAccessStrategy).insert(eq(element), eq(Element.class), argumentCaptor.capture());
|
||||
|
||||
assertThat(argumentCaptor.getValue().getParts()) //
|
||||
.extracting("name", "value", "targetType") //
|
||||
.containsExactly(
|
||||
tuple("list_list_container", CONTAINER_ID, Long.class), // the top level id
|
||||
tuple("list_list_container_key", 3, Integer.class), // midlevel key
|
||||
tuple("list_container_key", 6, Integer.class) // lowlevel key
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Container {
|
||||
|
||||
@@ -129,4 +169,16 @@ public class DefaultJdbcInterpreterUnitTests {
|
||||
|
||||
static class Element1 {
|
||||
}
|
||||
|
||||
|
||||
static class ListListContainer {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
List<ListContainer> listContainers;
|
||||
}
|
||||
|
||||
private static class ListContainer {
|
||||
List<Element> elements;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,14 @@ import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assume;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
@@ -461,8 +464,7 @@ public class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
template.delete(chain4, Chain4.class);
|
||||
|
||||
assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM CHAIN0", emptyMap(), Long.class)) //
|
||||
.isEqualTo(0);
|
||||
assertThat(count("CHAIN0")).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-359
|
||||
@@ -492,8 +494,224 @@ public class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
template.delete(chain4, NoIdChain4.class);
|
||||
|
||||
assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM CHAIN0", emptyMap(), Long.class)) //
|
||||
.isEqualTo(0);
|
||||
assertThat(count("CHAIN0")).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-223
|
||||
public void saveAndLoadLongChainOfListsWithoutIds() {
|
||||
|
||||
NoIdListChain4 saved = template.save(createNoIdTree());
|
||||
|
||||
assertThat(saved.four).describedAs("Something went wrong during saving").isNotNull();
|
||||
|
||||
NoIdListChain4 reloaded = template.findById(saved.four, NoIdListChain4.class);
|
||||
|
||||
assertIsUnchanged(saved, reloaded);
|
||||
|
||||
template.deleteById(saved.four, NoIdListChain4.class);
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(count("NO_ID_LIST_CHAIN4")).describedAs("Chain4 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_LIST_CHAIN3")).describedAs("Chain3 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_LIST_CHAIN2")).describedAs("Chain2 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_LIST_CHAIN1")).describedAs("Chain1 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_LIST_CHAIN0")).describedAs("Chain0 elements got deleted").isEqualTo(0);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an instance of {@link NoIdListChain4} with the following properties:
|
||||
* <ul>
|
||||
* <li>Each element has two children with indices 0 and 1.</li>
|
||||
* <li>the xxxValue of each element is a {@literal v} followed by the indices used to navigate to the given instance.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@NotNull
|
||||
private JdbcAggregateTemplateIntegrationTests.NoIdListChain4 createNoIdTree() {
|
||||
|
||||
NoIdListChain4 chain4 = new NoIdListChain4();
|
||||
chain4.fourValue = "v";
|
||||
for (int _3 = 0; _3 <= 1; _3++) {
|
||||
|
||||
NoIdListChain3 c3 = new NoIdListChain3();
|
||||
c3.threeValue = chain4.fourValue + _3;
|
||||
chain4.chain3.add(c3);
|
||||
|
||||
for (int _2 = 0; _2 <= 1; _2++) {
|
||||
|
||||
NoIdListChain2 c2 = new NoIdListChain2();
|
||||
c2.twoValue = c3.threeValue + _2;
|
||||
c3.chain2.add(c2);
|
||||
|
||||
for (int _1 = 0; _1 <= 1; _1++) {
|
||||
|
||||
NoIdListChain1 c1 = new NoIdListChain1();
|
||||
c1.oneValue = c2.twoValue + _1;
|
||||
c2.chain1.add(c1);
|
||||
|
||||
for (int _0 = 0; _0 <= 1; _0++) {
|
||||
|
||||
NoIdListChain0 c0 = new NoIdListChain0();
|
||||
c0.zeroValue = c1.oneValue + _0;
|
||||
c1.chain0.add(c0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return chain4;
|
||||
}
|
||||
|
||||
private void assertIsUnchanged(NoIdListChain4 original, NoIdListChain4 reloaded) {
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(reloaded.fourValue).isEqualTo("v");
|
||||
softly.assertThat(reloaded.chain3).hasSize(2);
|
||||
for (int _3 = 0; _3 <= 1; _3++) {
|
||||
|
||||
NoIdListChain3 c3 = reloaded.chain3.get(_3);
|
||||
softly.assertThat(c3.threeValue).isEqualTo(original.fourValue + _3);
|
||||
softly.assertThat(c3.chain2).hasSize(2);
|
||||
|
||||
for (int _2 = 0; _2 <= 1; _2++) {
|
||||
|
||||
NoIdListChain2 c2 = c3.chain2.get(_2);
|
||||
softly.assertThat(c2.twoValue).isEqualTo(c3.threeValue + _2);
|
||||
softly.assertThat(c2.chain1).hasSize(2);
|
||||
|
||||
for (int _1 = 0; _1 <= 1; _1++) {
|
||||
|
||||
NoIdListChain1 c1 = c2.chain1.get(_1);
|
||||
softly.assertThat(c1.oneValue).isEqualTo(c2.twoValue + _1);
|
||||
softly.assertThat(c1.chain0).hasSize(2);
|
||||
|
||||
for (int _0 = 0; _0 <= 1; _0++) {
|
||||
|
||||
NoIdListChain0 c0 = c1.chain0.get(_0);
|
||||
softly.assertThat(c0.zeroValue).isEqualTo(c1.oneValue + _0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-223
|
||||
public void saveAndLoadLongChainOfMapsWithoutIds() {
|
||||
|
||||
NoIdMapChain4 saved = template.save(createNoIdMapTree());
|
||||
|
||||
assertThat(saved.four).isNotNull();
|
||||
|
||||
NoIdMapChain4 reloaded = template.findById(saved.four, NoIdMapChain4.class);
|
||||
|
||||
assertIsUnchanged(saved, reloaded);
|
||||
|
||||
template.deleteById(saved.four, NoIdMapChain4.class);
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(count("NO_ID_MAP_CHAIN4")).describedAs("Chain4 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_MAP_CHAIN3")).describedAs("Chain3 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_MAP_CHAIN2")).describedAs("Chain2 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_MAP_CHAIN1")).describedAs("Chain1 elements got deleted").isEqualTo(0);
|
||||
softly.assertThat(count("NO_ID_MAP_CHAIN0")).describedAs("Chain0 elements got deleted").isEqualTo(0);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JdbcAggregateTemplateIntegrationTests.NoIdMapChain4 createNoIdMapTree() {
|
||||
|
||||
NoIdMapChain4 chain4 = new NoIdMapChain4();
|
||||
chain4.fourValue = "v";
|
||||
for (int _3 = 0; _3 <= 1; _3++) {
|
||||
|
||||
NoIdMapChain3 c3 = new NoIdMapChain3();
|
||||
c3.threeValue = chain4.fourValue + _3;
|
||||
chain4.chain3.put(asString(_3), c3);
|
||||
|
||||
for (int _2 = 0; _2 <= 1; _2++) {
|
||||
|
||||
NoIdMapChain2 c2 = new NoIdMapChain2();
|
||||
c2.twoValue = c3.threeValue + _2;
|
||||
c3.chain2.put(asString(_2), c2);
|
||||
|
||||
for (int _1 = 0; _1 <= 1; _1++) {
|
||||
|
||||
NoIdMapChain1 c1 = new NoIdMapChain1();
|
||||
c1.oneValue = c2.twoValue + _1;
|
||||
c2.chain1.put(asString(_1), c1);
|
||||
|
||||
for (int _0 = 0; _0 <= 1; _0++) {
|
||||
|
||||
NoIdMapChain0 c0 = new NoIdMapChain0();
|
||||
c0.zeroValue = c1.oneValue + _0;
|
||||
c1.chain0.put(asString(_0), c0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return chain4;
|
||||
}
|
||||
|
||||
private void assertIsUnchanged(NoIdMapChain4 original, NoIdMapChain4 reloaded) {
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(reloaded.fourValue).isEqualTo("v");
|
||||
softly.assertThat(reloaded.chain3).hasSize(2);
|
||||
for (int _3 = 0; _3 <= 1; _3++) {
|
||||
|
||||
NoIdMapChain3 c3 = reloaded.chain3.get(asString(_3));
|
||||
softly.assertThat(c3.threeValue).isEqualTo(original.fourValue + _3);
|
||||
softly.assertThat(c3.chain2).hasSize(2);
|
||||
|
||||
for (int _2 = 0; _2 <= 1; _2++) {
|
||||
|
||||
NoIdMapChain2 c2 = c3.chain2.get(asString(_2));
|
||||
softly.assertThat(c2.twoValue).isEqualTo(c3.threeValue + _2);
|
||||
softly.assertThat(c2.chain1).hasSize(2);
|
||||
|
||||
for (int _1 = 0; _1 <= 1; _1++) {
|
||||
|
||||
NoIdMapChain1 c1 = c2.chain1.get(asString(_1));
|
||||
softly.assertThat(c1.oneValue).isEqualTo(c2.twoValue + _1);
|
||||
softly.assertThat(c1.chain0).hasSize(2);
|
||||
|
||||
for (int _0 = 0; _0 <= 1; _0++) {
|
||||
|
||||
NoIdMapChain0 c0 = c1.chain0.get(asString(_0));
|
||||
softly.assertThat(c0.zeroValue).isEqualTo(c1.oneValue + _0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private static String asString(int i) {
|
||||
|
||||
return "_" + i;
|
||||
}
|
||||
|
||||
private Long count(String tableName) {
|
||||
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM " + tableName, emptyMap(), Long.class);
|
||||
}
|
||||
|
||||
private static void assumeNot(String dbProfileName) {
|
||||
@@ -659,4 +877,60 @@ public class JdbcAggregateTemplateIntegrationTests {
|
||||
String fourValue;
|
||||
NoIdChain3 chain3;
|
||||
}
|
||||
|
||||
/**
|
||||
* One may think of ChainN as a chain with N further elements
|
||||
*/
|
||||
static class NoIdListChain0 {
|
||||
String zeroValue;
|
||||
}
|
||||
|
||||
static class NoIdListChain1 {
|
||||
String oneValue;
|
||||
List<NoIdListChain0> chain0 = new ArrayList<>();
|
||||
}
|
||||
|
||||
static class NoIdListChain2 {
|
||||
String twoValue;
|
||||
List<NoIdListChain1> chain1 = new ArrayList<>();
|
||||
}
|
||||
|
||||
static class NoIdListChain3 {
|
||||
String threeValue;
|
||||
List<NoIdListChain2> chain2 = new ArrayList<>();
|
||||
}
|
||||
|
||||
static class NoIdListChain4 {
|
||||
@Id Long four;
|
||||
String fourValue;
|
||||
List<NoIdListChain3> chain3 = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* One may think of ChainN as a chain with N further elements
|
||||
*/
|
||||
static class NoIdMapChain0 {
|
||||
String zeroValue;
|
||||
}
|
||||
|
||||
static class NoIdMapChain1 {
|
||||
String oneValue;
|
||||
Map<String, NoIdMapChain0> chain0 = new HashMap<>();
|
||||
}
|
||||
|
||||
static class NoIdMapChain2 {
|
||||
String twoValue;
|
||||
Map<String, NoIdMapChain1> chain1 = new HashMap<>();
|
||||
}
|
||||
|
||||
static class NoIdMapChain3 {
|
||||
String threeValue;
|
||||
Map<String, NoIdMapChain2> chain2 = new HashMap<>();
|
||||
}
|
||||
|
||||
static class NoIdMapChain4 {
|
||||
@Id Long four;
|
||||
String fourValue;
|
||||
Map<String, NoIdMapChain3> chain3 = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
@@ -39,7 +37,7 @@ import org.springframework.data.util.ClassTypeInformation;
|
||||
public class BasicRelationalConverterAggregateReferenceUnitTests {
|
||||
|
||||
JdbcMappingContext context = new JdbcMappingContext();
|
||||
RelationalConverter converter = new BasicJdbcConverter(context);
|
||||
RelationalConverter converter = new BasicJdbcConverter(context, mock(RelationResolver.class));
|
||||
|
||||
RelationalPersistentEntity<?> entity = context.getRequiredPersistentEntity(DummyEntity.class);
|
||||
|
||||
|
||||
@@ -25,18 +25,13 @@ import lombok.RequiredArgsConstructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
@@ -58,16 +53,27 @@ public class DefaultDataAccessStrategyUnitTests {
|
||||
NamedParameterJdbcOperations namedJdbcOperations = mock(NamedParameterJdbcOperations.class);
|
||||
JdbcOperations jdbcOperations = mock(JdbcOperations.class);
|
||||
RelationalMappingContext context = new JdbcMappingContext();
|
||||
JdbcConverter converter = new BasicJdbcConverter(context, new JdbcCustomConversions(),
|
||||
new DefaultJdbcTypeFactory(jdbcOperations));
|
||||
|
||||
HashMap<String, Object> additionalParameters = new HashMap<>();
|
||||
ArgumentCaptor<SqlParameterSource> paramSourceCaptor = ArgumentCaptor.forClass(SqlParameterSource.class);
|
||||
|
||||
DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy( //
|
||||
new SqlGeneratorSource(context), //
|
||||
context, //
|
||||
converter, //
|
||||
namedJdbcOperations);
|
||||
JdbcConverter converter;
|
||||
DefaultDataAccessStrategy accessStrategy;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
DelegatingDataAccessStrategy relationResolver = new DelegatingDataAccessStrategy();
|
||||
|
||||
converter = new BasicJdbcConverter(context, relationResolver,
|
||||
new JdbcCustomConversions(), new DefaultJdbcTypeFactory(jdbcOperations));
|
||||
accessStrategy = new DefaultDataAccessStrategy( //
|
||||
new SqlGeneratorSource(context), //
|
||||
context, //
|
||||
converter, //
|
||||
namedJdbcOperations);
|
||||
|
||||
relationResolver.setDelegate(accessStrategy);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-146
|
||||
public void additionalParameterForIdDoesNotLeadToDuplicateParameters() {
|
||||
@@ -100,7 +106,9 @@ public class DefaultDataAccessStrategyUnitTests {
|
||||
@Test // DATAJDBC-235
|
||||
public void considersConfiguredWriteConverter() {
|
||||
|
||||
JdbcConverter converter = new BasicJdbcConverter(context,
|
||||
DelegatingDataAccessStrategy relationResolver = new DelegatingDataAccessStrategy();
|
||||
|
||||
JdbcConverter converter = new BasicJdbcConverter(context, relationResolver,
|
||||
new JdbcCustomConversions(Arrays.asList(BooleanToStringConverter.INSTANCE, StringToBooleanConverter.INSTANCE)),
|
||||
new DefaultJdbcTypeFactory(jdbcOperations));
|
||||
|
||||
@@ -110,6 +118,8 @@ public class DefaultDataAccessStrategyUnitTests {
|
||||
converter, //
|
||||
namedJdbcOperations);
|
||||
|
||||
relationResolver.setDelegate(accessStrategy);
|
||||
|
||||
ArgumentCaptor<String> sqlCaptor = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
EntityWithBoolean entity = new EntityWithBoolean(ORIGINAL_ID, true);
|
||||
|
||||
@@ -18,8 +18,7 @@ package org.springframework.data.jdbc.core.convert;
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -45,16 +44,19 @@ import javax.naming.OperationNotSupportedException;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.Embedded;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -580,32 +582,52 @@ public class EntityRowMapperUnitTests {
|
||||
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
|
||||
|
||||
// the ID of the entity is used to determine what kind of ResultSet is needed for subsequent selects.
|
||||
doReturn(new HashSet<>(asList(new Trivial(1L, "one"), new Trivial(2L, "two")))).when(accessStrategy)
|
||||
.findAllByProperty(eq(ID_FOR_ENTITY_NOT_REFERENCING_MAP), any(RelationalPersistentProperty.class));
|
||||
HashSet<Trivial> trivials = new HashSet<>(asList( //
|
||||
new Trivial(1L, "one"), //
|
||||
new Trivial(2L, "two") //
|
||||
));
|
||||
|
||||
doReturn(new HashSet<>(asList( //
|
||||
HashSet<SimpleEntry<Integer, Trivial>> simpleEntriesWithInts = new HashSet<>(asList( //
|
||||
new SimpleEntry<>(1, new Trivial(1L, "one")), //
|
||||
new SimpleEntry<>(2, new Trivial(2L, "two")) //
|
||||
));
|
||||
|
||||
HashSet<SimpleEntry<String, Trivial>> simpleEntriesWithStringKeys = new HashSet<>(asList( //
|
||||
new SimpleEntry<>("one", new Trivial(1L, "one")), //
|
||||
new SimpleEntry<>("two", new Trivial(2L, "two")) //
|
||||
))).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_REFERENCING_MAP),
|
||||
));
|
||||
|
||||
doReturn(trivials).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_NOT_REFERENCING_MAP),
|
||||
any(RelationalPersistentProperty.class));
|
||||
|
||||
doReturn(new HashSet<>(asList( //
|
||||
new SimpleEntry<>(1, new Trivial(1L, "one")), //
|
||||
new SimpleEntry<>(2, new Trivial(2L, "tow")) //
|
||||
))).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_REFERENCING_LIST),
|
||||
doReturn(simpleEntriesWithStringKeys).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_REFERENCING_MAP),
|
||||
any(RelationalPersistentProperty.class));
|
||||
|
||||
JdbcConverter converter = new BasicJdbcConverter(context, new JdbcCustomConversions(),
|
||||
doReturn(simpleEntriesWithInts).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_REFERENCING_LIST),
|
||||
any(RelationalPersistentProperty.class));
|
||||
|
||||
doReturn(trivials).when(accessStrategy).findAllByPath(identifierOfValue(ID_FOR_ENTITY_NOT_REFERENCING_MAP),
|
||||
any(PersistentPropertyPath.class));
|
||||
|
||||
doReturn(simpleEntriesWithStringKeys).when(accessStrategy)
|
||||
.findAllByPath(identifierOfValue(ID_FOR_ENTITY_REFERENCING_MAP), any(PersistentPropertyPath.class));
|
||||
|
||||
doReturn(simpleEntriesWithInts).when(accessStrategy)
|
||||
.findAllByPath(identifierOfValue(ID_FOR_ENTITY_REFERENCING_LIST), any(PersistentPropertyPath.class));
|
||||
|
||||
BasicJdbcConverter converter = new BasicJdbcConverter(context, accessStrategy, new JdbcCustomConversions(),
|
||||
JdbcTypeFactory.unsupported());
|
||||
|
||||
return new EntityRowMapper<>( //
|
||||
(RelationalPersistentEntity<T>) context.getRequiredPersistentEntity(type), //
|
||||
//
|
||||
converter, //
|
||||
accessStrategy //
|
||||
converter //
|
||||
);
|
||||
}
|
||||
|
||||
private Identifier identifierOfValue(long value) {
|
||||
return ArgumentMatchers.argThat(argument -> argument.toMap().containsValue(value));
|
||||
}
|
||||
|
||||
private static ResultSet mockResultSet(List<String> columns, Object... values) {
|
||||
|
||||
Assert.isTrue( //
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEnti
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.Aliased;
|
||||
import org.springframework.data.relational.core.sql.Table;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link SqlGenerator}.
|
||||
@@ -51,6 +52,8 @@ import org.springframework.data.relational.core.sql.Table;
|
||||
*/
|
||||
public class SqlGeneratorUnitTests {
|
||||
|
||||
static final Identifier BACKREF = Identifier.of("backref", "some-value", String.class);
|
||||
|
||||
SqlGenerator sqlGenerator;
|
||||
NamingStrategy namingStrategy = new PrefixingNamingStrategy();
|
||||
RelationalMappingContext context = new JdbcMappingContext(namingStrategy);
|
||||
@@ -149,7 +152,7 @@ public class SqlGeneratorUnitTests {
|
||||
public void findAllByProperty() {
|
||||
|
||||
// this would get called when ListParent is the element type of a Set
|
||||
String sql = sqlGenerator.getFindAllByProperty("backref", null, false);
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF, null, false);
|
||||
|
||||
assertThat(sql).contains("SELECT", //
|
||||
"dummy_entity.id1 AS id1", //
|
||||
@@ -165,11 +168,33 @@ public class SqlGeneratorUnitTests {
|
||||
"WHERE dummy_entity.backref = :backref");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-223
|
||||
public void findAllByPropertyWithMultipartIdentifier() {
|
||||
|
||||
// this would get called when ListParent is the element type of a Set
|
||||
String sql = sqlGenerator.getFindAllByProperty(Identifier.of("backref", "some-value", String.class).withPart("backref_key", "key-value", Object.class), null, false);
|
||||
|
||||
assertThat(sql).contains("SELECT", //
|
||||
"dummy_entity.id1 AS id1", //
|
||||
"dummy_entity.x_name AS x_name", //
|
||||
"dummy_entity.x_other AS x_other", //
|
||||
"ref.x_l1id AS ref_x_l1id", //
|
||||
"ref.x_content AS ref_x_content", //
|
||||
"ref_further.x_l2id AS ref_further_x_l2id", //
|
||||
"ref_further.x_something AS ref_further_x_something", //
|
||||
"FROM dummy_entity ", //
|
||||
"LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1", //
|
||||
"LEFT OUTER JOIN second_level_referenced_entity AS ref_further ON ref_further.referenced_entity = ref.x_l1id", //
|
||||
"dummy_entity.backref = :backref",
|
||||
"dummy_entity.backref_key = :backref_key"
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131, DATAJDBC-111
|
||||
public void findAllByPropertyWithKey() {
|
||||
|
||||
// this would get called when ListParent is th element type of a Map
|
||||
String sql = sqlGenerator.getFindAllByProperty("backref", "key-column", false);
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF, "key-column", false);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, dummy_entity.x_name AS x_name, " //
|
||||
+ "dummy_entity.x_other AS x_other, " //
|
||||
@@ -184,14 +209,14 @@ public class SqlGeneratorUnitTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAJDBC-130
|
||||
public void findAllByPropertyOrderedWithoutKey() {
|
||||
sqlGenerator.getFindAllByProperty("back-ref", null, true);
|
||||
sqlGenerator.getFindAllByProperty(BACKREF, null, true);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131, DATAJDBC-111
|
||||
public void findAllByPropertyWithKeyOrdered() {
|
||||
|
||||
// this would get called when ListParent is th element type of a Map
|
||||
String sql = sqlGenerator.getFindAllByProperty("backref", "key-column", true);
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF, "key-column", true);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, dummy_entity.x_name AS x_name, " //
|
||||
+ "dummy_entity.x_other AS x_other, " //
|
||||
@@ -297,7 +322,7 @@ public class SqlGeneratorUnitTests {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getFindAllByProperty("backref", "key-column", true)).isEqualToIgnoringCase( //
|
||||
assertThat(sqlGenerator.getFindAllByProperty(BACKREF, "key-column", true)).isEqualToIgnoringCase( //
|
||||
"SELECT " //
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " //
|
||||
+ "entity_with_read_only_property.x_name AS x_name, " //
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
|
||||
import org.springframework.data.jdbc.core.convert.DelegatingDataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
|
||||
@@ -77,11 +78,13 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
|
||||
RelationalMappingContext context = new JdbcMappingContext();
|
||||
NamedParameterJdbcOperations operations = createIdGeneratingOperations();
|
||||
JdbcConverter converter = new BasicJdbcConverter(context, new JdbcCustomConversions(),
|
||||
DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy();
|
||||
JdbcConverter converter = new BasicJdbcConverter(context, delegatingDataAccessStrategy, new JdbcCustomConversions(),
|
||||
new DefaultJdbcTypeFactory(operations.getJdbcOperations()));
|
||||
SqlGeneratorSource generatorSource = new SqlGeneratorSource(context);
|
||||
|
||||
this.dataAccessStrategy = spy(new DefaultDataAccessStrategy(generatorSource, context, converter, operations));
|
||||
delegatingDataAccessStrategy.setDelegate(dataAccessStrategy);
|
||||
|
||||
JdbcRepositoryFactory factory = new JdbcRepositoryFactory(dataAccessStrategy, context, converter, publisher,
|
||||
operations);
|
||||
|
||||
@@ -84,7 +84,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
|
||||
factoryBean.setDataAccessStrategy(dataAccessStrategy);
|
||||
factoryBean.setMappingContext(mappingContext);
|
||||
factoryBean.setConverter(new BasicJdbcConverter(mappingContext, JdbcTypeFactory.unsupported()));
|
||||
factoryBean.setConverter(new BasicJdbcConverter(mappingContext, dataAccessStrategy));
|
||||
factoryBean.setApplicationEventPublisher(publisher);
|
||||
factoryBean.setBeanFactory(beanFactory);
|
||||
factoryBean.afterPropertiesSet();
|
||||
@@ -111,7 +111,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
public void afterPropertiesSetDefaultsNullablePropertiesCorrectly() {
|
||||
|
||||
factoryBean.setMappingContext(mappingContext);
|
||||
factoryBean.setConverter(new BasicJdbcConverter(mappingContext, JdbcTypeFactory.unsupported()));
|
||||
factoryBean.setConverter(new BasicJdbcConverter(mappingContext, dataAccessStrategy));
|
||||
factoryBean.setApplicationEventPublisher(publisher);
|
||||
factoryBean.setBeanFactory(beanFactory);
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
@@ -20,13 +20,13 @@ import java.util.Optional;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.RelationResolver;
|
||||
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
|
||||
@@ -81,7 +82,11 @@ public class TestConfiguration {
|
||||
DataAccessStrategy defaultDataAccessStrategy(
|
||||
@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, RelationalMappingContext context,
|
||||
JdbcConverter converter) {
|
||||
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, converter, template);
|
||||
|
||||
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(new SqlGeneratorSource(context),
|
||||
context, converter, template);
|
||||
|
||||
return defaultDataAccessStrategy;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -98,9 +103,14 @@ public class TestConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
JdbcConverter relationalConverter(RelationalMappingContext mappingContext, CustomConversions conversions,
|
||||
@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template) {
|
||||
return new BasicJdbcConverter(mappingContext, conversions,
|
||||
new DefaultJdbcTypeFactory(template.getJdbcOperations()));
|
||||
JdbcConverter relationalConverter(RelationalMappingContext mappingContext, @Lazy RelationResolver relationResolver,
|
||||
CustomConversions conversions, @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template) {
|
||||
|
||||
return new BasicJdbcConverter( //
|
||||
mappingContext, //
|
||||
relationResolver, //
|
||||
conversions, //
|
||||
new DefaultJdbcTypeFactory(template.getJdbcOperations()) //
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,28 +100,196 @@ CREATE TABLE NO_ID_CHAIN4
|
||||
|
||||
CREATE TABLE NO_ID_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN4
|
||||
(
|
||||
FOUR BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 40) PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN3 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN2 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN1_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY,
|
||||
NO_ID_LIST_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN1 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN4
|
||||
(
|
||||
FOUR BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 40) PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN3 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN2 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN1_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY,
|
||||
NO_ID_MAP_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN1 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
@@ -116,3 +116,171 @@ CREATE TABLE NO_ID_CHAIN0
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN4
|
||||
(
|
||||
FOUR BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN3 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN2 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN1_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY,
|
||||
NO_ID_LIST_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN1 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN4
|
||||
(
|
||||
FOUR BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN3 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN2 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN1_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY,
|
||||
NO_ID_MAP_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN1 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
@@ -125,3 +125,170 @@ CREATE TABLE NO_ID_CHAIN0
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN4
|
||||
(
|
||||
FOUR BIGINT IDENTITY PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN3 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN2 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN1_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY,
|
||||
NO_ID_LIST_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN1 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN4
|
||||
(
|
||||
FOUR BIGINT IDENTITY PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN3 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN2 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN1_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY,
|
||||
NO_ID_MAP_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN1 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
@@ -116,3 +116,170 @@ CREATE TABLE NO_ID_CHAIN0
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN4
|
||||
(
|
||||
FOUR BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN3 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN2 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN1_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY,
|
||||
NO_ID_LIST_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN1 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN4
|
||||
(
|
||||
FOUR BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN3 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN2 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN1_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY,
|
||||
NO_ID_MAP_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN1 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
@@ -136,3 +136,171 @@ CREATE TABLE NO_ID_CHAIN0
|
||||
NO_ID_CHAIN4 BIGINT,
|
||||
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN4
|
||||
(
|
||||
FOUR SERIAL PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN3 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN2 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_LIST_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_LIST_CHAIN4 BIGINT,
|
||||
NO_ID_LIST_CHAIN4_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN3_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN2_KEY BIGINT,
|
||||
NO_ID_LIST_CHAIN1_KEY BIGINT,
|
||||
PRIMARY KEY (NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY,
|
||||
NO_ID_LIST_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_LIST_CHAIN1 (
|
||||
NO_ID_LIST_CHAIN4,
|
||||
NO_ID_LIST_CHAIN4_KEY,
|
||||
NO_ID_LIST_CHAIN3_KEY,
|
||||
NO_ID_LIST_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN4
|
||||
(
|
||||
FOUR SERIAL PRIMARY KEY,
|
||||
FOUR_VALUE VARCHAR(20)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN3
|
||||
(
|
||||
THREE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY),
|
||||
FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN2
|
||||
(
|
||||
TWO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN3 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN1
|
||||
(
|
||||
ONE_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN2 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE NO_ID_MAP_CHAIN0
|
||||
(
|
||||
ZERO_VALUE VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN4 BIGINT,
|
||||
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
|
||||
NO_ID_MAP_CHAIN1_KEY VARCHAR(20),
|
||||
PRIMARY KEY (NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY,
|
||||
NO_ID_MAP_CHAIN1_KEY),
|
||||
FOREIGN KEY (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
) REFERENCES NO_ID_MAP_CHAIN1 (
|
||||
NO_ID_MAP_CHAIN4,
|
||||
NO_ID_MAP_CHAIN4_KEY,
|
||||
NO_ID_MAP_CHAIN3_KEY,
|
||||
NO_ID_MAP_CHAIN2_KEY
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user