diff --git a/README_zh.md b/README_zh.md index d5d4d678f30e20573039f4ac0810e5095a0e0c26..585114fbbee4c12c1301b1fab2fed99a42f18b09 100644 --- a/README_zh.md +++ b/README_zh.md @@ -171,7 +171,7 @@ public class UserRepositoryIntegrationTest { ```xml io.easybest - spring-boot-starter-data-mybatis + spring-data-mybatis-boot-starter 2.0.1.RELEASE ``` diff --git a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java index 8a0f8aee184b7e4d7896972cce3d407cf9a8bab7..c91308b984efc1e39d0dab287ac6a086bf0282ee 100644 --- a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java +++ b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java @@ -15,20 +15,29 @@ */ package org.springframework.data.mybatis.autoconfigure; +import java.util.List; + import javax.sql.DataSource; +import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.data.mybatis.mapping.MybatisEntityClassScanner; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; import org.springframework.data.mybatis.repository.MybatisRepository; import org.springframework.data.mybatis.repository.config.EnableMybatisRepositories; import org.springframework.data.mybatis.repository.config.MybatisRepositoryConfigExtension; @@ -57,11 +66,27 @@ import org.springframework.data.mybatis.repository.support.MybatisRepositoryFact @ConditionalOnBean(DataSource.class) @ConditionalOnClass(MybatisRepository.class) @ConditionalOnMissingBean({ MybatisRepositoryFactoryBean.class, MybatisRepositoryConfigExtension.class }) -@ConditionalOnProperty(prefix = "spring.data.mybatis.repositories", name = "enabled", havingValue = "true", +@ConditionalOnProperty(prefix = SpringDataMybatisProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) @Import(MybatisRepositoriesAutoConfigureRegistrar.class) @AutoConfigureAfter({ MybatisAutoConfiguration.class, TaskExecutionAutoConfiguration.class }) @EnableConfigurationProperties(SpringDataMybatisProperties.class) public class MybatisRepositoriesAutoConfiguration { + @Bean + @ConditionalOnMissingBean + public MybatisMappingContext mybatisMappingContext(BeanFactory beanFactory, SqlSessionTemplate sqlSessionTemplate) + throws ClassNotFoundException { + MybatisMappingContext context = new MybatisMappingContext(sqlSessionTemplate); + + List packages = EntityScanPackages.get(beanFactory).getPackageNames(); + if (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) { + packages = AutoConfigurationPackages.get(beanFactory); + } + if (!packages.isEmpty()) { + context.setInitialEntitySet(MybatisEntityClassScanner.scan(packages)); + } + return context; + } + } diff --git a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java index 04750d75683a34672ccf95458efca0cbabfd65e0..547fc7ba054de174f6a9b20ed62095c303bf0803 100644 --- a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java +++ b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java @@ -21,7 +21,6 @@ import java.util.Locale; import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; import org.springframework.data.mybatis.repository.config.EnableMybatisRepositories; import org.springframework.data.mybatis.repository.config.MybatisRepositoryConfigExtension; import org.springframework.data.repository.config.BootstrapMode; @@ -38,8 +37,6 @@ class MybatisRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfig private BootstrapMode bootstrapMode = null; - private ResourceLoader resourceLoader; - @Override protected Class getAnnotation() { return EnableMybatisRepositories.class; @@ -52,7 +49,7 @@ class MybatisRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfig @Override protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { - return new MybatisRepositoryConfigExtension(this.resourceLoader); + return new MybatisRepositoryConfigExtension(); } @Override @@ -73,12 +70,6 @@ class MybatisRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfig } } - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - super.setResourceLoader(resourceLoader); - } - @EnableMybatisRepositories private static class EnableMybatisRepositoriesConfiguration { diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FieldNamingStrategy.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/Fetch.java similarity index 83% rename from spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FieldNamingStrategy.java rename to spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/Fetch.java index 280cc6d558ddeee6c032d45f9764dc878c959bdd..926184071c08ea8c7839a6bf996d26bef60080b5 100644 --- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FieldNamingStrategy.java +++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/Fetch.java @@ -21,14 +21,15 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Specify field naming strategy for property. + * Define the fetching strategy used for the given association. + * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.2 */ -@Target({ ElementType.TYPE }) +@Target({ ElementType.METHOD, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) -public @interface FieldNamingStrategy { +public @interface Fetch { - String value() default ""; + FetchMode value(); } diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FetchMode.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FetchMode.java new file mode 100644 index 0000000000000000000000000000000000000000..ce90f4f2c02158e68c88b45c130a13932e285855 --- /dev/null +++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FetchMode.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-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.mybatis.annotation; + +/** + * Fetch options on associations. Defines more of the "how" of fetching, whereas JPA + * {@link javax.persistence.FetchType} focuses on the "when". + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public enum FetchMode { + + /** + * Use a secondary select for each individual entity, collection, or join load. + */ + SELECT, + /** + * Use an outer join to load the related entities, collections or joins. + */ + JOIN, + /** + * Available for collections only. When accessing a non-initialized collection, this + * fetch mode will trigger loading all elements of all collections of the same role + * for all owners associated with the persistence context using a single secondary + * select. + */ + SUBSELECT + +} diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java index 94a7fee7a306d264d318776b0aafecde9733b3fe..b72dcbdf75db93d9c391ab390c867160dbf696d0 100644 --- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java +++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java @@ -29,6 +29,6 @@ import java.lang.annotation.Target; @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) public @interface JdbcType { - String value() default ""; + String value(); } diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java index 13f551c6bf79e35f4cdd117e70d8e3f72a523316..96d82e53d205c2b999262a3b7d55c3cc9fc34c8a 100644 --- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java +++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java @@ -29,6 +29,6 @@ import java.lang.annotation.Target; @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER }) public @interface TypeHandler { - String value(); + Class value(); } diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java index 55a81c6d97c441845f5b83fe73884ff869be7ffb..6ed0cefaaf72f1dd4d172db1e99b2a1d87be9c29 100644 --- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java +++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java @@ -55,7 +55,7 @@ public abstract class Auditfalse - 2.3.3.RELEASE - 2.3.3.RELEASE + 2.3.4.RELEASE + 2.3.4.RELEASE 3.5.5 @@ -73,18 +73,18 @@ 4.13 5.6.2 1.3.72 - 1.3.8 + 1.3.9 1.2.3 1.18.12 3.3.3 1.10.0 4.3.1 - Dysprosium-SR11 + Dysprosium-SR12 1.3.8 1.2.1 2.2.19 1.7.26 - 5.2.8.RELEASE + 5.2.9.RELEASE 1.1.1.RELEASE 2.0.0.RELEASE 1.14.3 @@ -356,12 +356,6 @@ 1.18.10.0 - - org.jfrog.buildinfo - artifactory-maven-plugin - 2.7.0 - - diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/AuditingInterceptor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/AuditingInterceptor.java similarity index 97% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/AuditingInterceptor.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/AuditingInterceptor.java index 118404394bc33d419c658ccf80447b54f9caa92e..ef4687a87aff4d36cb252ce006849e8366d1c1d8 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/AuditingInterceptor.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/AuditingInterceptor.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mybatis.domain.support; +package org.springframework.data.mybatis.auditing; import java.util.Map; diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/MybatisAuditingHandler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/MybatisAuditingHandler.java similarity index 97% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/MybatisAuditingHandler.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/MybatisAuditingHandler.java index 0dd85e468c0df77314c0c18fc39850a8c0b0626d..09d4f21728b39039d33bd6ef22ca300c3eba2d0d 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/MybatisAuditingHandler.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/MybatisAuditingHandler.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mybatis.domain.support; +package org.springframework.data.mybatis.auditing; import org.mybatis.spring.SqlSessionTemplate; diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java index d085bfed45c4979c9a9d5700073240ad96c5d4f4..caf9011e1b0bd1b04b47656c722d5045a4401433 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java @@ -15,24 +15,34 @@ */ package org.springframework.data.mybatis.mapping; +import java.beans.Introspector; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import javax.persistence.Entity; import javax.persistence.NamedNativeQueries; import javax.persistence.NamedNativeQuery; import javax.persistence.NamedQueries; +import org.mybatis.spring.SqlSessionTemplate; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.Property; +import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; -import org.springframework.data.mybatis.repository.MybatisRepository; +import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy; +import org.springframework.data.mybatis.dialect.Dialect; +import org.springframework.data.mybatis.dialect.internal.DatabaseMetaDataDialectResolutionInfoAdapter; +import org.springframework.data.mybatis.dialect.internal.StandardDialectResolver; +import org.springframework.data.mybatis.mapping.model.Domain; +import org.springframework.data.mybatis.mapping.model.Model; +import org.springframework.data.mybatis.precompiler.SimpleMybatisPrecompiler; import org.springframework.data.util.TypeInformation; -import org.springframework.util.CollectionUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; /** * {@link MappingContext} implementation based on JPA annotations. @@ -40,20 +50,86 @@ import org.springframework.util.MultiValueMap; * @author JARVIS SONG * @since 1.0.0 */ -public class MybatisMappingContext - extends AbstractMappingContext, MybatisPersistentProperty> { +public class MybatisMappingContext extends + AbstractMappingContext, MybatisPersistentProperty> implements InitializingBean { + + private static final SnakeCaseFieldNamingStrategy SNAKE_CASE_FIELD_NAMING_STRATEGY = new SnakeCaseFieldNamingStrategy(); + + private final SqlSessionTemplate sqlSessionTemplate; + + private final Dialect dialect; private FieldNamingStrategy fieldNamingStrategy; private Map namedQueries = new HashMap<>(); - private MultiValueMap, Class> entityRepositoryMapping = new LinkedMultiValueMap<>(); + private Map, Domain> domainCache = new HashMap<>(); + + public MybatisMappingContext(SqlSessionTemplate sqlSessionTemplate) { + this.sqlSessionTemplate = sqlSessionTemplate; + this.dialect = StandardDialectResolver.INSTANCE.resolveDialect(new DatabaseMetaDataDialectResolutionInfoAdapter( + sqlSessionTemplate.getConfiguration().getEnvironment().getDataSource())); + } + + @Override + public void afterPropertiesSet() { + super.afterPropertiesSet(); + + if (null == this.fieldNamingStrategy) { + if (null != this.sqlSessionTemplate + && this.sqlSessionTemplate.getConfiguration().isMapUnderscoreToCamelCase()) { + this.fieldNamingStrategy = SNAKE_CASE_FIELD_NAMING_STRATEGY; + } + else { + this.fieldNamingStrategy = PropertyNameFieldNamingStrategy.INSTANCE; + } + } + + // initialize models + this.domainCache = this.getManagedTypes().stream().map(TypeInformation::getType) + .filter(clz -> clz.isAnnotationPresent(Entity.class)).collect(Collectors.toMap(clz -> clz, + clz -> new Domain(this, null, clz, Introspector.decapitalize(clz.getSimpleName())))); + + this.domainCache.values().stream().forEach(Domain::initialize); + + // generate mybatis mappers + this.domainCache.values().stream().forEach(domain -> new SimpleMybatisPrecompiler(this, domain).compile()); + } + + public Model getModel(Class clz) { + return this.domainCache.get(clz); + } + + public Model getRequiredModel(Class type) throws MappingException { + + Model model = getModel(type); + + if (model != null) { + return model; + } + + throw new MappingException(String.format("Couldn't find Model for type %s!", type)); + } @Override protected MybatisPersistentEntityImpl createPersistentEntity(TypeInformation typeInformation) { + MybatisPersistentEntityImpl entity = new MybatisPersistentEntityImpl<>(typeInformation); + this.processNamedQueries(entity); + return entity; + } + + @Override + protected MybatisPersistentProperty createPersistentProperty(Property property, + MybatisPersistentEntityImpl owner, SimpleTypeHolder simpleTypeHolder) { + + return new MybatisPersistentPropertyImpl(property, owner, simpleTypeHolder); + } - MybatisPersistentEntityImpl entity = new MybatisPersistentEntityImpl(typeInformation); + public String getNamedQuery(String name) { + return this.namedQueries.get(name); + } + private void processNamedQueries(MybatisPersistentEntityImpl entity) { javax.persistence.NamedQuery namedQuery = entity.findAnnotation(javax.persistence.NamedQuery.class); if ((null != namedQuery)) { this.namedQueries.put(namedQuery.name(), namedQuery.query()); @@ -75,41 +151,22 @@ public class MybatisMappingContext this.namedQueries.put(nq.name(), nq.query()); } } - - return entity; - } - - @Override - protected MybatisPersistentProperty createPersistentProperty(Property property, - MybatisPersistentEntityImpl owner, SimpleTypeHolder simpleTypeHolder) { - return new MybatisPersistentPropertyImpl(property, owner, simpleTypeHolder, this.fieldNamingStrategy); } public void setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) { this.fieldNamingStrategy = fieldNamingStrategy; } - public String getNamedQuery(String name) { - return this.namedQueries.get(name); + public SqlSessionTemplate getSqlSessionTemplate() { + return this.sqlSessionTemplate; } - public void setEntityRepositoryMapping(MultiValueMap, Class> entityRepositoryMapping) { - this.entityRepositoryMapping = entityRepositoryMapping; + public Dialect getDialect() { + return this.dialect; } - public Class getRepositoryInterface(Class entityClass) { - List> repositories = this.entityRepositoryMapping.get(entityClass); - if (CollectionUtils.isEmpty(repositories)) { - return null; - } - - if (repositories.size() == 1) { - return repositories.get(0); - } - - return repositories.stream().filter(r -> MybatisRepository.class.isAssignableFrom(r)).findFirst() - .orElse(repositories.get(0)); - + public FieldNamingStrategy getFieldNamingStrategy() { + return this.fieldNamingStrategy; } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java index 46ea499fd5b005500c0f9b66a983bee9d4f1a7ba..d116bcdca65fa6eac93356612cc30ff55fb7ae86 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java @@ -16,7 +16,6 @@ package org.springframework.data.mybatis.mapping; import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mybatis.mapping.model.Table; /** * Interface for a MyBatis-specific entity. @@ -27,9 +26,11 @@ import org.springframework.data.mybatis.mapping.model.Table; */ public interface MybatisPersistentEntity extends PersistentEntity { - Table getTable(); - - boolean hasCompositeId(); + /** + * Returns whether this entity represents a composite primary key. + * @return whether composite primary key + */ + boolean isCompositePrimaryKey(); Class getIdClass(); diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java index d7b526b582f20eb9455788ce75d714a2892fdac8..32413cd54a95734575a7dd7f1a59295bc5af33fa 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java @@ -18,14 +18,10 @@ package org.springframework.data.mybatis.mapping; import java.util.Comparator; import javax.persistence.EmbeddedId; -import javax.persistence.Entity; import javax.persistence.IdClass; import org.springframework.data.mapping.model.BasicPersistentEntity; -import org.springframework.data.mybatis.mapping.model.Table; -import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; -import org.springframework.util.StringUtils; /** * Implementation of {@link MybatisPersistentEntity}. @@ -36,68 +32,29 @@ import org.springframework.util.StringUtils; class MybatisPersistentEntityImpl extends BasicPersistentEntity implements MybatisPersistentEntity { - private Lazy table; - MybatisPersistentEntityImpl(TypeInformation information) { - this(information, null); + this(information, (o1, o2) -> o1.isIdProperty() ? -1 : 1); } MybatisPersistentEntityImpl(TypeInformation information, Comparator comparator) { super(information, comparator); - this.table = Lazy.of(() -> { - - String schema = null; - String catalog = null; - String name = null; - if (this.isAnnotationPresent(javax.persistence.Table.class)) { - javax.persistence.Table t = this.getRequiredAnnotation(javax.persistence.Table.class); - schema = t.schema(); - catalog = t.catalog(); - name = t.name(); - } - if (StringUtils.isEmpty(name)) { - Entity entity = this.findAnnotation(Entity.class); - name = ((null != entity) && StringUtils.hasText(entity.name())) ? entity.name() - : this.getType().getSimpleName(); - } - Table table = new Table(schema, catalog, name); - return table; - }); - } - - @Override - public Table getTable() { - return this.table.get(); - } - - @Override - public String getName() { - Entity entity = this.findAnnotation(Entity.class); - return ((null != entity) && StringUtils.hasText(entity.name())) ? entity.name() : super.getName(); } @Override - public boolean hasCompositeId() { + public boolean isCompositePrimaryKey() { if (this.isAnnotationPresent(IdClass.class)) { return true; } - if (this.hasIdProperty()) { - return this.getRequiredIdProperty().isAnnotationPresent(EmbeddedId.class); - } - return false; + + return this.hasIdProperty() ? this.getRequiredIdProperty().isAnnotationPresent(EmbeddedId.class) : false; } @Override public Class getIdClass() { - if (this.isAnnotationPresent(IdClass.class)) { - IdClass idClass = this.getRequiredAnnotation(IdClass.class); - return idClass.value(); - } - if (this.hasIdProperty()) { - return this.getRequiredIdProperty().getActualType(); - } - return null; + + return this.isAnnotationPresent(IdClass.class) ? this.getRequiredAnnotation(IdClass.class).value() + : (this.hasIdProperty() ? this.getRequiredIdProperty().getActualType() : null); } @Override diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java index ad82c60738f9d79f4ab09ae65851dfa5e15dd61f..c36a77a950bf2a69ee82826cf09a8869532093a3 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java @@ -16,7 +16,6 @@ package org.springframework.data.mybatis.mapping; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.mybatis.mapping.model.Column; /** * Interface for a MyBatis-specific {@link PersistentProperty}. @@ -32,8 +31,6 @@ public interface MybatisPersistentProperty extends PersistentProperty> UPDATEABLE_ANNOTATIONS; - private static final Map, JdbcType> JAVA_MAPPED_TO_JDBC_TYPES; - static { Set> annotations = new HashSet<>(); @@ -119,28 +98,6 @@ class MybatisPersistentPropertyImpl extends AnnotationBasedPersistentProperty, JdbcType> javaTypesMappedToJdbcTypes = new HashMap<>(); - javaTypesMappedToJdbcTypes.put(String.class, JdbcType.VARCHAR); - javaTypesMappedToJdbcTypes.put(java.math.BigDecimal.class, JdbcType.NUMERIC); - javaTypesMappedToJdbcTypes.put(boolean.class, JdbcType.BIT); - javaTypesMappedToJdbcTypes.put(byte.class, JdbcType.TINYINT); - javaTypesMappedToJdbcTypes.put(short.class, JdbcType.SMALLINT); - javaTypesMappedToJdbcTypes.put(int.class, JdbcType.INTEGER); - javaTypesMappedToJdbcTypes.put(long.class, JdbcType.BIGINT); - javaTypesMappedToJdbcTypes.put(float.class, JdbcType.REAL); - javaTypesMappedToJdbcTypes.put(double.class, JdbcType.DOUBLE); - javaTypesMappedToJdbcTypes.put(byte[].class, JdbcType.VARBINARY); - javaTypesMappedToJdbcTypes.put(java.util.Date.class, JdbcType.TIMESTAMP); - javaTypesMappedToJdbcTypes.put(java.sql.Date.class, JdbcType.DATE); - javaTypesMappedToJdbcTypes.put(java.sql.Time.class, JdbcType.TIME); - javaTypesMappedToJdbcTypes.put(java.sql.Timestamp.class, JdbcType.TIMESTAMP); - javaTypesMappedToJdbcTypes.put(Boolean.class, JdbcType.BIT); - javaTypesMappedToJdbcTypes.put(Integer.class, JdbcType.INTEGER); - javaTypesMappedToJdbcTypes.put(Long.class, JdbcType.BIGINT); - javaTypesMappedToJdbcTypes.put(Float.class, JdbcType.REAL); - javaTypesMappedToJdbcTypes.put(Double.class, JdbcType.DOUBLE); - - JAVA_MAPPED_TO_JDBC_TYPES = Collections.unmodifiableMap(javaTypesMappedToJdbcTypes); } private final @Nullable Boolean usePropertyAccess; @@ -155,17 +112,14 @@ class MybatisPersistentPropertyImpl extends AnnotationBasedPersistentProperty isEntity; - private final Lazy column; - /** * Creates a new {@link AnnotationBasedPersistentProperty}. * @param property must not be {@literal null}. * @param owner must not be {@literal null}. * @param simpleTypeHolder simple type holder - * @param fieldNamingStrategy naming strategy */ MybatisPersistentPropertyImpl(Property property, PersistentEntity owner, - SimpleTypeHolder simpleTypeHolder, FieldNamingStrategy fieldNamingStrategy) { + SimpleTypeHolder simpleTypeHolder) { super(property, owner, simpleTypeHolder); this.isAssociation = Lazy.of(() -> ASSOCIATION_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent)); @@ -177,99 +131,6 @@ class MybatisPersistentPropertyImpl extends AnnotationBasedPersistentProperty ID_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent)); this.isEntity = Lazy.of(() -> ENTITY_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent)); - this.column = Lazy.of(() -> { - String columnName = PropertyNameFieldNamingStrategy.INSTANCE.getFieldName(this); - Class actualType = this.getType(); - - javax.persistence.Column column = this.findAnnotation(javax.persistence.Column.class); - if (null != column && StringUtils.hasText(column.name())) { - columnName = column.name(); - } - else { - OrderColumn orderColumn = this.findAnnotation(OrderColumn.class); - if (null != orderColumn && StringUtils.hasText(orderColumn.name())) { - columnName = orderColumn.name(); - } - else if (null != fieldNamingStrategy) { - columnName = fieldNamingStrategy.getFieldName(this); - } - } - JdbcType jdbcType = JdbcType.UNDEFINED; - org.springframework.data.mybatis.annotation.JdbcType jdbcTypeAnn = this - .findAnnotation(org.springframework.data.mybatis.annotation.JdbcType.class); - if (null != jdbcTypeAnn) { - jdbcType = JdbcType.valueOf(jdbcTypeAnn.value()); - } - else if (this.isAnnotationPresent(Temporal.class)) { - Temporal temporal = this.getRequiredAnnotation(Temporal.class); - switch (temporal.value()) { - - case DATE: - jdbcType = JdbcType.DATE; - break; - case TIME: - jdbcType = JdbcType.TIME; - break; - case TIMESTAMP: - jdbcType = JdbcType.TIMESTAMP; - break; - } - } - else if (actualType.isEnum()) { - jdbcType = JdbcType.VARCHAR; - } - else { - if (this.isAnnotationPresent(Lob.class)) { - jdbcType = (actualType != String.class) ? JdbcType.BLOB : JdbcType.CLOB; - } - else { - JdbcType jt = JAVA_MAPPED_TO_JDBC_TYPES.get(actualType); - if (null != jt) { - jdbcType = jt; - } - } - } - Column col = new Column(columnName, jdbcType); - if (this.isVersionProperty()) { - col.setVersion(true); - } - col.setJavaType(actualType); - col.setPrimaryKey(this.isIdProperty.get()); - TypeHandler typeHandler = this.findAnnotation(TypeHandler.class); - if (null != typeHandler && StringUtils.hasText(typeHandler.value())) { - try { - col.setTypeHandler(ClassUtils.forName(typeHandler.value(), this.getClass().getClassLoader())); - } - catch (Exception ex) { - throw new MappingException(ex.getMessage(), ex); - } - } - else { - - if (this.isEnumerated()) { - Enumerated enumerated = this.getRequiredAnnotation(Enumerated.class); - if (enumerated.value() == EnumType.ORDINAL) { - col.setTypeHandler(EnumOrdinalTypeHandler.class); - } - else { - col.setTypeHandler(EnumTypeHandler.class); - } - } - else if (actualType == Long.class && jdbcType == JdbcType.TIMESTAMP) { - col.setTypeHandler(UnixTimestampDateTypeHandler.class); - } - else if (actualType == Date.class && jdbcType == JdbcType.BIGINT) { - col.setTypeHandler(DateUnixTimestampTypeHandler.class); - } - - } - return col; - }); - } - - @Override - public Column getColumn() { - return this.column.get(); } @Override diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java index 875c64b571e045d1524def8aa11444ece8e7c264..4c1f92e6f23dd92d4d9269e740822da26db13a18 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java @@ -15,63 +15,12 @@ */ package org.springframework.data.mybatis.mapping.model; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import lombok.Data; -import lombok.experimental.Accessors; - /** - * Association. + * . * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.2 */ -@Data -@Accessors(chain = true) -public class Association implements Serializable { - - private static final long serialVersionUID = 3169794115053267639L; - - private String property; - - private String javaType; - - private String select; - - private String fetch; - - private String targetTable; - - private List joinColumns = new ArrayList<>(); - - private List results = new LinkedList<>(); - - public Association addResult(ColumnResult cr) { - this.results.add(cr); - return this; - } - - public Association addJoinColumn(JoinColumn jc) { - this.joinColumns.add(jc); - return this; - } - - @Data - @Accessors(chain = true) - public static class JoinColumn { - - private String name; - - private String referencedColumnName; - - public JoinColumn(String name, String referencedColumnName) { - this.name = name; - this.referencedColumnName = referencedColumnName; - } - - } +public interface Association extends Model { } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java index 04327ead6ae8599e85ce847c57cf43c9ba73d0d2..7485f0d315ddd099c5941303809097a62947cee4 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java @@ -15,81 +15,287 @@ */ package org.springframework.data.mybatis.mapping.model; +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.time.chrono.JapaneseDate; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import javax.persistence.Enumerated; +import javax.persistence.Lob; +import javax.persistence.Temporal; + +import org.apache.ibatis.type.EnumOrdinalTypeHandler; +import org.apache.ibatis.type.EnumTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeAliasRegistry; +import org.springframework.data.mybatis.annotation.TypeHandler; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; +import org.springframework.data.mybatis.mapping.handler.DateUnixTimestampTypeHandler; +import org.springframework.data.mybatis.mapping.handler.UnixTimestampDateTypeHandler; +import org.springframework.util.StringUtils; + /** - * Column model. + * . * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.2 */ -@Getter -@Setter -@ToString -public class Column { +public class Column implements Component, Cloneable { + + private static final long serialVersionUID = 6881902687485454726L; + + protected static Map, String> TYPE_ALIAS = new HashMap<>(); - private static Map, String> TYPE_ALIAS = new HashMap<>(); + private static final Map, JdbcType> JAVA_TYPE_MAPPING; static { TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry(); Map> typeAliases = typeAliasRegistry.getTypeAliases(); typeAliases.entrySet().stream().forEach(entry -> TYPE_ALIAS.put(entry.getValue(), entry.getKey())); + + Map, JdbcType> map = new HashMap<>(); + map.put(Boolean.class, JdbcType.BOOLEAN); + map.put(boolean.class, JdbcType.BOOLEAN); + map.put(Byte.class, JdbcType.BIT); + map.put(byte.class, JdbcType.BIT); + map.put(Short.class, JdbcType.SMALLINT); + map.put(short.class, JdbcType.SMALLINT); + map.put(Integer.class, JdbcType.INTEGER); + map.put(int.class, JdbcType.INTEGER); + map.put(Long.class, JdbcType.BIGINT); + map.put(long.class, JdbcType.BIGINT); + map.put(Float.class, JdbcType.FLOAT); + map.put(float.class, JdbcType.FLOAT); + map.put(Double.class, JdbcType.DOUBLE); + map.put(double.class, JdbcType.DOUBLE); + map.put(Character.class, JdbcType.VARCHAR); + map.put(char.class, JdbcType.VARCHAR); + map.put(Reader.class, JdbcType.CLOB); + map.put(String.class, JdbcType.VARCHAR); + map.put(BigInteger.class, JdbcType.BIGINT); + map.put(BigDecimal.class, JdbcType.DECIMAL); + map.put(InputStream.class, JdbcType.BLOB); + map.put(Byte[].class, JdbcType.BLOB); + map.put(byte[].class, JdbcType.BLOB); + map.put(Object.class, JdbcType.OTHER); + map.put(Date.class, JdbcType.TIMESTAMP); + map.put(java.sql.Date.class, JdbcType.DATE); + map.put(java.sql.Time.class, JdbcType.TIME); + map.put(java.sql.Timestamp.class, JdbcType.TIMESTAMP); + map.put(Instant.class, JdbcType.TIMESTAMP); + map.put(LocalDateTime.class, JdbcType.TIMESTAMP_WITH_TIMEZONE); + map.put(LocalDate.class, JdbcType.DATE); + map.put(LocalTime.class, JdbcType.TIME); + map.put(OffsetDateTime.class, JdbcType.TIMESTAMP); + map.put(OffsetTime.class, JdbcType.TIME); + map.put(ZonedDateTime.class, JdbcType.TIMESTAMP); + map.put(Month.class, JdbcType.INTEGER); + map.put(Year.class, JdbcType.INTEGER); + map.put(YearMonth.class, JdbcType.VARCHAR); + map.put(JapaneseDate.class, JdbcType.TIMESTAMP); + JAVA_TYPE_MAPPING = Collections.unmodifiableMap(map); + } + + protected final Model model; + + private final MybatisPersistentProperty property; + + protected final String columnAlias; + + protected Identifier name; + + protected String propertyName; + + protected JdbcType jdbcType; + + protected Class javaType; + + protected Class typeHandler; + + public Column(Model model, MybatisPersistentProperty property) { + this.model = model; + this.property = property; + + javax.persistence.Column columnAnn = property.findAnnotation(javax.persistence.Column.class); + if (null != columnAnn && StringUtils.hasText(columnAnn.name())) { + this.name = Identifier.toIdentifier(columnAnn.name()); + } + else { + this.name = Identifier + .toIdentifier(model.getMappingContext().getFieldNamingStrategy().getFieldName(property)); + } + this.javaType = property.getType(); + this.jdbcType = this.processJdbcType(property); + this.typeHandler = this.processTypeHandler(property); + + String[] aliasArray = model.getAlias().split("\\."); + int pos = 1; + if (aliasArray.length == pos) { + this.columnAlias = this.name.getText(); + this.propertyName = property.getName(); + } + else { + String[] aa = new String[aliasArray.length - pos]; + System.arraycopy(aliasArray, pos, aa, 0, aa.length); + String pre = Arrays.stream(aa).collect(Collectors.joining(".")); + this.propertyName = pre + '.' + property.getName(); + + if (model instanceof Embedding) { + if (aa.length == 1) { + this.columnAlias = this.name.getText(); + } + else { + String[] bb = new String[aa.length - 1]; + System.arraycopy(aa, 0, bb, 0, bb.length); + this.columnAlias = Arrays.stream(bb).collect(Collectors.joining(".")) + '.' + this.name.getText(); + } + } + else { + this.columnAlias = pre + '.' + this.name.getText(); + } + + } } - private Identifier name; + private JdbcType processJdbcType(MybatisPersistentProperty property) { - private JdbcType jdbcType; + org.springframework.data.mybatis.annotation.JdbcType jdbcTypeAnn = property + .findAnnotation(org.springframework.data.mybatis.annotation.JdbcType.class); + if (null != jdbcTypeAnn) { + return JdbcType.valueOf(jdbcTypeAnn.value()); + } - private Class javaType; + if (property.isAnnotationPresent(Temporal.class)) { + Temporal temporalAnn = property.getRequiredAnnotation(Temporal.class); + switch (temporalAnn.value()) { + case DATE: + return JdbcType.DATE; + case TIME: + return JdbcType.TIME; + case TIMESTAMP: + return JdbcType.TIMESTAMP; + } + } - private Class typeHandler; + if (property.getType().isEnum()) { + Enumerated enumeratedAnn = property.findAnnotation(Enumerated.class); + if (null != enumeratedAnn) { + switch (enumeratedAnn.value()) { + case ORDINAL: + return JdbcType.INTEGER; + case STRING: + return JdbcType.VARCHAR; + } + } + return JdbcType.VARCHAR; + } - private boolean primaryKey; + if (property.isAnnotationPresent(Lob.class)) { + if (CharSequence.class.isAssignableFrom(property.getType())) { + return JdbcType.CLOB; + } + return JdbcType.BLOB; + } - private boolean version; + JdbcType jdbcType = JAVA_TYPE_MAPPING.get(property.getType()); - public Column(String name) { - this.name = Identifier.toIdentifier(name); + return (null != jdbcType) ? jdbcType : JdbcType.UNDEFINED; } - public Column(String name, JdbcType jdbcType) { - this.name = Identifier.toIdentifier(name); - this.jdbcType = jdbcType; + private Class processTypeHandler(MybatisPersistentProperty property) { + TypeHandler typeHandler = property.findAnnotation(TypeHandler.class); + if (null != typeHandler) { + return typeHandler.value(); + } + + if (property.isEnumerated()) { + Enumerated enumeratedAnn = property.getRequiredAnnotation(Enumerated.class); + switch (enumeratedAnn.value()) { + case ORDINAL: + return EnumOrdinalTypeHandler.class; + case STRING: + return EnumTypeHandler.class; + } + } + + if (property.getType() == Long.class && this.getJdbcType() == JdbcType.TIMESTAMP) { + return UnixTimestampDateTypeHandler.class; + } + if (property.getType() == Date.class && this.getJdbcType() == JdbcType.BIGINT) { + return DateUnixTimestampTypeHandler.class; + } + return null; + } + + @Override + public Model getModel() { + return this.model; + } + + public String getColumnAlias() { + return this.columnAlias; } - public Column(Identifier name, JdbcType jdbcType) { + public Identifier getName() { + return this.name; + } + + public void setName(Identifier name) { this.name = name; + } + + public String getPropertyName() { + return this.propertyName; + } + + public void setPropertyName(String propertyName) { + this.propertyName = propertyName; + } + + public JdbcType getJdbcType() { + return this.jdbcType; + } + + public void setJdbcType(JdbcType jdbcType) { this.jdbcType = jdbcType; } - public boolean isString() { - return this.javaType == String.class - || (null != this.javaType && CharSequence.class.isAssignableFrom(this.javaType)); + public Class getJavaType() { + return this.javaType; } - public boolean hasJdbcType() { - return null != this.jdbcType; + public void setJavaType(Class javaType) { + this.javaType = javaType; } - public boolean hasJavaType() { - return null != this.jdbcType; + public Class getTypeHandler() { + return this.typeHandler; } - public boolean hasTypeHandler() { - return null != this.typeHandler; + public void setTypeHandler(Class typeHandler) { + this.typeHandler = typeHandler; } - public String getJdbcTypeString() { - if (null == this.jdbcType) { - return null; - } - return this.jdbcType.name(); + @Override + protected Column clone() throws CloneNotSupportedException { + return (Column) super.clone(); } public String getJavaTypeString() { @@ -104,11 +310,15 @@ public class Column { return this.javaType.getName(); } - public String getTypeHandlerString() { - if (null == this.typeHandler) { - return null; - } - return this.typeHandler.getName(); + public boolean isString() { + JdbcType jdbcType = this.getJdbcType(); + return jdbcType == JdbcType.VARCHAR || jdbcType == JdbcType.CHAR || jdbcType == JdbcType.CLOB + || jdbcType == JdbcType.NVARCHAR || jdbcType == JdbcType.NCHAR || jdbcType == JdbcType.LONGNVARCHAR + || jdbcType == JdbcType.LONGVARCHAR; + } + + public MybatisPersistentProperty getProperty() { + return this.property; } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ColumnResult.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Component.java similarity index 74% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ColumnResult.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Component.java index 337f3ab190933a99b05781f66c69cffd43d0f06f..f005b059698004a02902152dc1a35e04e68d6464 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ColumnResult.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Component.java @@ -17,27 +17,18 @@ package org.springframework.data.mybatis.mapping.model; import java.io.Serializable; -import lombok.Data; - /** * . * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.2 */ -@Data -public class ColumnResult implements Serializable { - - private boolean primaryKey; - - private String property; - - private String column; - - private String javaType; - - private String jdbcType; +public interface Component extends Serializable { - private String typeHandler; + /** + * Belong to. + * @return model + */ + Model getModel(); } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/CompositePrimaryKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/CompositePrimaryKey.java new file mode 100644 index 0000000000000000000000000000000000000000..ff6450e8d119ff8a5bb13e9014eae43900cc430a --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/CompositePrimaryKey.java @@ -0,0 +1,91 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; +import org.springframework.data.util.StreamUtils; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class CompositePrimaryKey implements PrimaryKey { + + private final Map columns = new LinkedHashMap<>(); + + private final Model model; + + public CompositePrimaryKey(Model model, MybatisPersistentEntity entity) { + this.model = model; + + StreamUtils.createStreamFromIterator(entity.iterator()).filter(PersistentProperty::isIdProperty).forEach(p -> { + + if (p.isEmbeddable()) { + MybatisPersistentEntity embeddedEntity = model.getMappingContext() + .getRequiredPersistentEntity(p.getType()); + embeddedEntity.forEach(ep -> { + + Column column = new Column(model, ep); + column.setPropertyName(p.getName() + '.' + ep.getName()); + this.addColumn(column); + }); + } + else { + Column column = new Column(model, p); + this.addColumn(column); + } + + }); + + } + + public void addColumn(Column column) { + this.columns.put(column.getName().getCanonicalName(), column); + } + + @Override + public boolean isComposited() { + return true; + } + + @Override + public Collection getColumns() { + return this.columns.values(); + } + + @Override + public Class getType() { + return this.model.getMappingEntity().getIdClass(); + } + + @Override + public Column findColumn(String name) { + return this.columns.get(name); + } + + @Override + public Model getModel() { + return this.model; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Domain.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Domain.java new file mode 100644 index 0000000000000000000000000000000000000000..7a32e978ffcfdc10d73e80e723e11130942433a7 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Domain.java @@ -0,0 +1,346 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.persistence.Entity; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +import org.springframework.data.mapping.PropertyPath; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; +import org.springframework.data.util.StreamUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class Domain implements Model { + + private static final long serialVersionUID = 4850421315538416089L; + + protected final MybatisMappingContext mappingContext; + + protected final MybatisPersistentEntity entity; + + protected final String alias; + + protected Table table; + + protected Model owner; + + protected PrimaryKey primaryKey; + + protected Map normalColumns; // columnName -> column + + protected Map versionColumns; + + protected List embeddings; + + protected List oneToOneAssociations; + + protected List manyToOneAssociations; + + protected List oneToManyAssociations; + + protected List manyToManyAssociations; + + public Domain(MybatisMappingContext mappingContext, Model owner, Class entityClass, String alias) { + this.mappingContext = mappingContext; + this.owner = owner; + this.entity = mappingContext.getRequiredPersistentEntity(entityClass); + if (null != owner) { + this.alias = owner.getAlias() + '.' + alias; + } + else { + this.alias = alias; + } + + this.internalInitialize(); + } + + public void initialize() { + if (null != this.owner) { + return; + } + + this.initializeOneToOneAssociations(); + this.initializeManyToOneAssociations(); + this.initializeOneToManyAssociations(); + this.initializeManyToManyAssociations(); + } + + private void internalInitialize() { + this.initializeTable(); + this.initializePrimaryKey(); + this.initializeNormalColumns(); + this.initializeVersionColumns(); + this.initializeEmbeddedDomains(); + } + + private void initializeManyToManyAssociations() { + this.manyToManyAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> p.isAnnotationPresent(ManyToMany.class)) + .map(p -> new ManyToManyAssociation(this.mappingContext, this, p, p.getName())) + .collect(Collectors.toList()); + } + + private void initializeOneToManyAssociations() { + this.oneToManyAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> p.isAnnotationPresent(OneToMany.class)) + .map(p -> new OneToManyAssociation(this.mappingContext, this, p, p.getName())) + .collect(Collectors.toList()); + } + + private void initializeOneToOneAssociations() { + this.oneToOneAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> p.isAnnotationPresent(OneToOne.class)) + .map(p -> new OneToOneAssociation(this.mappingContext, this, p, p.getName())) + .collect(Collectors.toList()); + } + + private void initializeManyToOneAssociations() { + this.manyToOneAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> p.isAnnotationPresent(ManyToOne.class)) + .map(p -> new ManyToOneAssociation(this.mappingContext, this, p, p.getName())) + .collect(Collectors.toList()); + } + + private void initializeEmbeddedDomains() { + this.embeddings = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> !p.isIdProperty() && !p.isAssociation() && p.isEmbeddable()) + .map(p -> new EmbeddedDomain(this.mappingContext, this, p, p.getName())).collect(Collectors.toList()); + } + + private void initializeVersionColumns() { + this.versionColumns = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> p.isVersionProperty()).map(p -> new VersionColumn(this, p)) + .collect(Collectors.toMap(c -> c.getName().getCanonicalName(), c -> c)); + + } + + private void initializeNormalColumns() { + this.normalColumns = StreamUtils.createStreamFromIterator(this.entity.iterator()) + .filter(p -> !p.isIdProperty() && !p.isAssociation() && !p.isEmbeddable() && !p.isVersionProperty()) + .map(p -> new Column(this, p)).collect(Collectors.toMap(c -> c.getName().getCanonicalName(), c -> c)); + } + + private void initializePrimaryKey() { + if (!this.entity.hasIdProperty()) { + return; + } + if (!this.entity.isCompositePrimaryKey()) { + this.primaryKey = new SinglePrimaryKey(this, this.entity.getRequiredIdProperty()); + return; + } + + // composited primary key + this.primaryKey = new CompositePrimaryKey(this, this.entity); + } + + private void initializeTable() { + String schema = null; + String catalog = null; + String name = null; + if (this.entity.isAnnotationPresent(javax.persistence.Table.class)) { + javax.persistence.Table tableAnn = this.entity.getRequiredAnnotation(javax.persistence.Table.class); + schema = tableAnn.schema(); + catalog = tableAnn.catalog(); + name = tableAnn.name(); + } + if (StringUtils.isEmpty(name)) { + Entity entityAnn = this.entity.findAnnotation(Entity.class); + name = ((null != entityAnn) && StringUtils.hasText(entityAnn.name())) ? entityAnn.name() + : this.entity.getType().getSimpleName(); + } + this.table = new Table(schema, catalog, name); + } + + @Override + public Column findColumn(String name) { + if (null != this.primaryKey) { + Column column = this.primaryKey.findColumn(name); + if (null != column) { + return column; + } + } + if (!CollectionUtils.isEmpty(this.normalColumns)) { + Column column = this.normalColumns.get(name); + if (null != column) { + return column; + } + } + if (!CollectionUtils.isEmpty(this.versionColumns)) { + Column column = this.versionColumns.get(name); + if (null != column) { + return column; + } + } + if (!CollectionUtils.isEmpty(this.embeddings)) { + for (EmbeddedDomain embeddedDomain : this.embeddings) { + Column c = embeddedDomain.findColumn(name); + if (null != c) { + return c; + } + } + + } + + return null; + } + + @Override + public Column findColumnByPropertyName(String propertyName) { + Column column = null; + if (null != this.primaryKey) { + column = this.primaryKey.getColumns().stream().filter(c -> c.getPropertyName().equals(propertyName)) + .findFirst().orElse(null); + } + if (null == column && !CollectionUtils.isEmpty(this.normalColumns)) { + column = this.normalColumns.values().stream().filter(c -> c.getPropertyName().equals(propertyName)) + .findFirst().orElse(null); + } + if (null == column && !CollectionUtils.isEmpty(this.versionColumns)) { + column = this.versionColumns.values().stream().filter(c -> c.getPropertyName().equals(propertyName)) + .findFirst().orElse(null); + } + if (null == column && !CollectionUtils.isEmpty(this.embeddings)) { + column = this.embeddings.stream() + .map(embeddedDomain -> embeddedDomain.findColumnByPropertyName(propertyName)).filter(c -> null != c) + .findFirst().orElse(null); + } + return column; + } + + @Override + public Column findColumn(PropertyPath propertyPath) { + if (null == propertyPath) { + return null; + } + String path = propertyPath.toDotPath(); + return this.findColumnByPropertyName(path); + } + + @Override + public List findColumnByTypeHandler(Class typeHandlerClass) { + List columns = new ArrayList<>(); + if (null != this.primaryKey) { + columns.addAll(this.primaryKey.getColumns().stream().filter(c -> c.getTypeHandler() == typeHandlerClass) + .collect(Collectors.toList())); + } + + if (null != this.normalColumns) { + columns.addAll(this.normalColumns.values().stream().filter(c -> c.getTypeHandler() == typeHandlerClass) + .collect(Collectors.toList())); + } + + if (null != this.versionColumns) { + columns.addAll(this.versionColumns.values().stream().filter(c -> c.getTypeHandler() == typeHandlerClass) + .collect(Collectors.toList())); + } + + if (!CollectionUtils.isEmpty(this.embeddings)) { + for (EmbeddedDomain embeddedDomain : this.embeddings) { + columns.addAll(embeddedDomain.findColumnByTypeHandler(typeHandlerClass)); + } + + } + + return columns; + } + + @Override + public MybatisMappingContext getMappingContext() { + return this.mappingContext; + } + + @Override + public String getAlias() { + return this.alias; + } + + @Override + public Model getOwner() { + return this.owner; + } + + @Override + public Table getTable() { + return this.table; + } + + @Override + public MybatisPersistentEntity getMappingEntity() { + return this.entity; + } + + @Override + public PrimaryKey getPrimaryKey() { + return this.primaryKey; + } + + @Override + public Collection getNormalColumns() { + return (Collection) this.normalColumns.values(); + } + + @Override + public Collection getVersionColumns() { + return (Collection) this.versionColumns.values(); + } + + @Override + public Collection getEmbeddings() { + return (Collection) this.embeddings; + } + + @Override + public Collection getOneToOneAssociations() { + return (Collection) this.oneToOneAssociations; + } + + @Override + public Collection getManyToOneAssociations() { + return (Collection) this.manyToOneAssociations; + } + + @Override + public Collection getOneToManyAssociations() { + return (Collection) this.oneToManyAssociations; + } + + @Override + public Collection getManyToManyAssociations() { + return (Collection) this.manyToManyAssociations; + } + + public String getTableAlias() { + return this.alias; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisRepositoryPrepareProcessor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/EmbeddedDomain.java similarity index 38% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisRepositoryPrepareProcessor.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/EmbeddedDomain.java index eebd93d2a426237bbc94687ec95b82b527c49433..b878340d5bdd5b6b2049f64043daf8ab653c654b 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisRepositoryPrepareProcessor.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/EmbeddedDomain.java @@ -13,42 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mybatis.repository.query; +package org.springframework.data.mybatis.mapping.model; -import org.apache.ibatis.session.Configuration; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.data.repository.core.RepositoryInformation; -import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; /** - * {@link RepositoryProxyPostProcessor} that sets up interceptors to read metadata - * information from the invoked method. + * . * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.2 */ -public class MybatisRepositoryPrepareProcessor implements RepositoryProxyPostProcessor { +public class EmbeddedDomain extends Domain implements Embedding { + + private static final long serialVersionUID = 1341386972281765879L; - private final MybatisMappingContext mappingContext; + private final MybatisPersistentProperty property; - private final Configuration configuration; + public EmbeddedDomain(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property, + String alias) { + super(mappingContext, owner, property.getType(), alias); - private final Dialect dialect; + this.property = property; + } - public MybatisRepositoryPrepareProcessor(MybatisMappingContext mappingContext, Configuration configuration, - Dialect dialect) { - this.mappingContext = mappingContext; - this.configuration = configuration; - this.dialect = dialect; + public MybatisPersistentProperty getProperty() { + return this.property; } @Override - public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) { - new SimpleMybatisPrecompiler(this.mappingContext, this.configuration, this.dialect, repositoryInformation) - .precompile(); + public String getTableAlias() { + String alias = super.getTableAlias(); + return alias.substring(0, alias.lastIndexOf(".")); } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Embedding.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Embedding.java new file mode 100644 index 0000000000000000000000000000000000000000..76d80ae371dda9e5d6350b6ae35c733d3c005c51 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Embedding.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public interface Embedding extends Model { + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ForeignKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ForeignKey.java new file mode 100644 index 0000000000000000000000000000000000000000..c7c9bd990de7f502ebbe6b6fc40fcfff5e6f89d2 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ForeignKey.java @@ -0,0 +1,108 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.persistence.JoinColumns; + +import org.springframework.data.mapping.MappingException; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; +import org.springframework.util.StringUtils; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class ForeignKey implements Component { + + private static final long serialVersionUID = 2476229243396329609L; + + private final List columns = new LinkedList<>(); + + private final Model model; + + private final ManyToOneAssociation assModel; + + public ForeignKey(Model model, ManyToOneAssociation assModel, MybatisPersistentProperty property) { + this.model = model; + this.assModel = assModel; + + Set joinColumnAnns = new HashSet<>(); + JoinColumns joinColumnsAnn = property.findAnnotation(JoinColumns.class); + if (null != joinColumnsAnn && joinColumnsAnn.value().length > 0) { + joinColumnAnns.addAll(Arrays.asList(joinColumnsAnn.value())); + } + javax.persistence.JoinColumn joinColumnAnn = property.findAnnotation(javax.persistence.JoinColumn.class); + if (null != joinColumnAnn) { + joinColumnAnns.add(joinColumnAnn); + } + + if (!joinColumnAnns.isEmpty()) { + joinColumnAnns.stream().map(jc -> this.processJoinColumn(property, jc.name(), jc.referencedColumnName())) + .forEach(jc -> this.columns.add(jc)); + } + else { + this.columns.add(this.processJoinColumn(property, null, null)); + } + } + + private JoinColumn processJoinColumn(MybatisPersistentProperty property, String columnName, + String referencedColumnName) { + Model targetModel = this.model.getMappingContext().getRequiredModel(property.getActualType()); + PrimaryKey primaryKey = this.model.getPrimaryKey(); + if (StringUtils.isEmpty(referencedColumnName) && !(primaryKey instanceof SinglePrimaryKey)) { + throw new MappingException("Could not find referenced column name for: " + property); + } + + referencedColumnName = StringUtils.hasText(referencedColumnName) ? referencedColumnName + : primaryKey.getColumns().iterator().next().getName().getCanonicalName(); + Column referencedColumn = targetModel.findColumn(referencedColumnName); + if (null == referencedColumn) { + throw new MappingException("Could not find referenced column by " + referencedColumnName); + } + + Column foreign = new Column(this.assModel, referencedColumn.getProperty()); + foreign.setName(referencedColumn.getName()); + foreign.setJavaType(referencedColumn.getJavaType()); + foreign.setJdbcType(referencedColumn.getJdbcType()); + foreign.setTypeHandler(referencedColumn.getTypeHandler()); + Column local = new Column(this.model, property); + local.setName(Identifier.toIdentifier( + StringUtils.hasText(columnName) ? columnName : property.getName() + '_' + foreign.getName().getText())); + local.setJavaType(foreign.getJavaType()); + local.setJdbcType(foreign.getJdbcType()); + local.setTypeHandler(foreign.getTypeHandler()); + + return new JoinColumn(local, foreign); + } + + @Override + public Model getModel() { + return this.model; + } + + public List getColumns() { + return this.columns; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java index 3e8a59695b6d385fd222581eba9cae10d839156f..207bce775bede5caa8194495c58445b1d01dce9d 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java @@ -98,7 +98,7 @@ public class Identifier implements Comparable { if (null != this.dialect) { return this.render(this.dialect); } - return this.isQuoted() ? ('`' + this.getText() + '`') : this.getText(); + return this.isQuoted() ? ('"' + this.getText() + '"') : this.getText(); } public String getCanonicalName() { diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinColumn.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinColumn.java new file mode 100644 index 0000000000000000000000000000000000000000..0d67a41ce7eba60277ef8c4da85f303f568c4b24 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinColumn.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class JoinColumn implements Component { + + private static final long serialVersionUID = -8697900456930913224L; + + protected final Column local; + + protected final Column foreign; + + public JoinColumn(Column local, Column foreign) { + this.local = local; + this.foreign = foreign; + } + + @Override + public Model getModel() { + return null; + } + + public Column getLocal() { + return this.local; + } + + public Column getForeign() { + return this.foreign; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinTable.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinTable.java new file mode 100644 index 0000000000000000000000000000000000000000..1af63c4c647be3bdcd9b214f89e8628b906bda30 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinTable.java @@ -0,0 +1,147 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.data.mapping.MappingException; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; +import org.springframework.util.StringUtils; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class JoinTable implements Component { + + private final Model model; + + private final Model targetModel; + + private final ManyToManyAssociation assModel; + + private Table table; + + private final List joinColumns = new LinkedList<>(); + + private final List inverseJoinColumns = new LinkedList<>(); + + public JoinTable(Model model, ManyToManyAssociation assModel, MybatisPersistentProperty property) { + this.model = model; + this.assModel = assModel; + this.targetModel = model.getMappingContext().getRequiredModel(property.getActualType()); + this.initialize(property); + } + + private void initialize(MybatisPersistentProperty property) { + String schema = null; + String catalog = null; + String name = null; + if (property.isAnnotationPresent(javax.persistence.JoinTable.class)) { + javax.persistence.JoinTable tableAnn = property.getRequiredAnnotation(javax.persistence.JoinTable.class); + schema = tableAnn.schema(); + catalog = tableAnn.catalog(); + name = tableAnn.name(); + } + if (StringUtils.isEmpty(name)) { + name = this.model.getTable().getName().getText() + '_' + this.assModel.getTable().getName().getText(); + } + this.table = new Table(schema, catalog, name); + + if (property.isAnnotationPresent(javax.persistence.JoinTable.class)) { + javax.persistence.JoinTable tableAnn = property.getRequiredAnnotation(javax.persistence.JoinTable.class); + if (null != tableAnn.joinColumns() && tableAnn.joinColumns().length > 0) { + if (tableAnn.joinColumns().length > 0) { + for (javax.persistence.JoinColumn joinColumn : tableAnn.joinColumns()) { + this.joinColumns.add(this.processJoinColumn(this.model, joinColumn.name(), + joinColumn.referencedColumnName())); + } + } + if (null != tableAnn.inverseJoinColumns() && tableAnn.inverseJoinColumns().length > 0) { + for (javax.persistence.JoinColumn inverseJoinColumn : tableAnn.inverseJoinColumns()) { + this.inverseJoinColumns.add(this.processJoinColumn(this.assModel, inverseJoinColumn.name(), + inverseJoinColumn.referencedColumnName())); + } + + } + } + } + + if (this.joinColumns.isEmpty()) { + this.joinColumns.add(this.processJoinColumn(this.model, null, null)); + } + if (this.inverseJoinColumns.isEmpty()) { + this.inverseJoinColumns.add(this.processJoinColumn(this.assModel, null, null)); + } + + } + + private JoinColumn processJoinColumn(Model targetModel, String name, String referencedColumnName) { + PrimaryKey primaryKey = targetModel.getPrimaryKey(); + if (StringUtils.isEmpty(referencedColumnName) && !(primaryKey instanceof SinglePrimaryKey)) { + throw new MappingException("Could not find referenced column name for: " + targetModel.getAlias()); + } + referencedColumnName = StringUtils.hasText(referencedColumnName) ? referencedColumnName + : primaryKey.getColumns().iterator().next().getName().getCanonicalName(); + Column referencedColumn = targetModel.findColumn(referencedColumnName); + if (null == referencedColumn) { + throw new MappingException("Could not find referenced column by " + referencedColumnName); + } + + Column foreign = new Column(targetModel, referencedColumn.getProperty()); + foreign.setName(referencedColumn.getName()); + foreign.setJavaType(referencedColumn.getJavaType()); + foreign.setJdbcType(referencedColumn.getJdbcType()); + foreign.setTypeHandler(referencedColumn.getTypeHandler()); + + Column local = new Column(targetModel, referencedColumn.getProperty()); + local.setName(Identifier.toIdentifier(StringUtils.hasText(name) ? name + : targetModel.getTable().getName().getText() + '_' + foreign.getName().getText())); + local.setJavaType(foreign.getJavaType()); + local.setJdbcType(foreign.getJdbcType()); + local.setTypeHandler(foreign.getTypeHandler()); + return new JoinColumn(local, foreign); + } + + @Override + public Model getModel() { + return this.model; + } + + public Table getTable() { + return this.table; + } + + public List getJoinColumns() { + return this.joinColumns; + } + + public List getInverseJoinColumns() { + return this.inverseJoinColumns; + } + + public Model getTargetModel() { + return this.targetModel; + } + + public String getTableAlias() { + return "ass_" + this.assModel.getTableAlias(); + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToManyAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToManyAssociation.java new file mode 100644 index 0000000000000000000000000000000000000000..6c6623e56a85aa57b11872c7616a26d3f1744aaf --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToManyAssociation.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import javax.persistence.FetchType; +import javax.persistence.ManyToMany; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.data.mybatis.annotation.Fetch; +import org.springframework.data.mybatis.annotation.FetchMode; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class ManyToManyAssociation extends Domain implements Association { + + private static final long serialVersionUID = -4694636482266575894L; + + private final MybatisPersistentProperty property; + + protected FetchType fetchType; + + protected FetchMode fetchMode; + + protected final JoinTable joinTable; + + public ManyToManyAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property, + String alias) { + super(mappingContext, owner, property.getActualType(), alias); + this.property = property; + this.fetchType = (FetchType) AnnotationUtils.getValue(property.findAnnotation(ManyToMany.class), "fetch"); + Fetch fetch = property.findAnnotation(Fetch.class); + if (null != fetch) { + this.fetchMode = fetch.value(); + } + else { + this.fetchMode = FetchMode.SELECT; // default + } + this.joinTable = new JoinTable(owner, this, property); + } + + public MybatisPersistentProperty getProperty() { + return this.property; + } + + public String getFetchType() { + if (null == this.fetchType) { + return null; + } + return this.fetchType.name().toLowerCase(); + } + + public FetchMode getFetchMode() { + return this.fetchMode; + } + + public JoinTable getJoinTable() { + return this.joinTable; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToOneAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToOneAssociation.java new file mode 100644 index 0000000000000000000000000000000000000000..f597be809191e21794358df2f7ee60d1879bd240 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToOneAssociation.java @@ -0,0 +1,95 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.lang.annotation.Annotation; + +import javax.persistence.FetchType; +import javax.persistence.ManyToOne; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.data.mybatis.annotation.Fetch; +import org.springframework.data.mybatis.annotation.FetchMode; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class ManyToOneAssociation extends Domain implements Association { + + private static final long serialVersionUID = 2812139190023990667L; + + private final MybatisPersistentProperty property; + + protected FetchType fetchType; + + protected FetchMode fetchMode; + + protected ForeignKey foreignKey; + + public ManyToOneAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property, + String alias) { + super(mappingContext, owner, property.getType(), alias); + this.fetchType = (FetchType) AnnotationUtils.getValue(property.findAnnotation(this.getAnnotation()), "fetch"); + this.property = property; + Fetch fetch = property.findAnnotation(Fetch.class); + if (null != fetch) { + this.fetchMode = fetch.value(); + } + else { + this.fetchMode = FetchMode.SELECT; // default + } + + this.foreignKey = new ForeignKey(owner, this, property); + + } + + public String fetchType() { + if (null == this.fetchType) { + return null; + } + return this.fetchType.name().toLowerCase(); + } + + protected Class getAnnotation() { + return ManyToOne.class; + } + + public boolean isLeftJoin() { + return this.fetchMode == FetchMode.JOIN; + } + + public FetchType getFetchType() { + return this.fetchType; + } + + public FetchMode getFetchMode() { + return this.fetchMode; + } + + public ForeignKey getForeignKey() { + return this.foreignKey; + } + + public MybatisPersistentProperty getProperty() { + return this.property; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Collection.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Model.java similarity index 34% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Collection.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Model.java index 9d818d907a0b8f9901fed67efa84d06fc279581d..7bceda7442b84ef72f50c3d7b5f6b4c7d21199a8 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Collection.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Model.java @@ -16,92 +16,53 @@ package org.springframework.data.mybatis.mapping.model; import java.io.Serializable; -import java.util.ArrayList; +import java.util.Collection; import java.util.List; -import lombok.Data; -import lombok.experimental.Accessors; - -import org.springframework.util.StringUtils; +import org.springframework.data.mapping.PropertyPath; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; /** - * Collection association. + * . * * @author JARVIS SONG - * @since 2.1.0 + * @since 2.0.2 */ -@Data -@Accessors(chain = true) -public class Collection implements Serializable { - - private String property; - - private String ofType; - - private String column; - - private String select; - - private String fetch; - - private JoinTable joinTable; - - private List joinColumns = new ArrayList<>(); - - private String targetTable; +public interface Model extends Serializable { - private boolean manyToMany; + MybatisMappingContext getMappingContext(); - private String order; + String getAlias(); - public Collection addJoinColumn(JoinColumn jc) { - this.joinColumns.add(jc); - return this; - } + Model getOwner(); - public boolean isOrderBy() { - return StringUtils.hasText(this.order); - } + Table getTable(); - @Data - @Accessors(chain = true) - public static class JoinTable { + MybatisPersistentEntity getMappingEntity(); - private String tableName; + PrimaryKey getPrimaryKey(); - private List joinColumns = new ArrayList<>(); + Collection getNormalColumns(); - private List inverseJoinColumns = new ArrayList<>(); + Collection getVersionColumns(); - public JoinTable(String tableName) { - this.tableName = tableName; - } + Collection getEmbeddings(); - public JoinTable addJoinColumn(JoinColumn jc) { - this.joinColumns.add(jc); - return this; - } + Collection getOneToOneAssociations(); - public JoinTable addInverseJoinColumns(JoinColumn jc) { - this.inverseJoinColumns.add(jc); - return this; - } + Collection getManyToOneAssociations(); - } + Collection getOneToManyAssociations(); - @Data - @Accessors(chain = true) - public static class JoinColumn { + Collection getManyToManyAssociations(); - private String name; + Column findColumn(String columnName); - private String referencedColumnName; + Column findColumn(PropertyPath propertyPath); - public JoinColumn(String name, String referencedColumnName) { - this.name = name; - this.referencedColumnName = referencedColumnName; - } + Column findColumnByPropertyName(String propertyName); - } + List findColumnByTypeHandler(Class typeHandlerClass); } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToManyAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToManyAssociation.java new file mode 100644 index 0000000000000000000000000000000000000000..697a784411ff8df896bc4d1e8ff0428678bea905 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToManyAssociation.java @@ -0,0 +1,137 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.LinkedList; +import java.util.List; + +import javax.persistence.FetchType; +import javax.persistence.JoinColumns; +import javax.persistence.OneToMany; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.data.mapping.MappingException; +import org.springframework.data.mybatis.annotation.Fetch; +import org.springframework.data.mybatis.annotation.FetchMode; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; +import org.springframework.util.StringUtils; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class OneToManyAssociation extends Domain implements Association { + + private static final long serialVersionUID = -5958192304583654899L; + + private final MybatisPersistentProperty property; + + protected FetchType fetchType; + + protected FetchMode fetchMode; + + protected final List joinColumns = new LinkedList<>(); + + protected final Model targetModel; + + public OneToManyAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property, + String alias) { + super(mappingContext, owner, property.getActualType(), alias); + this.property = property; + this.fetchType = (FetchType) AnnotationUtils.getValue(property.findAnnotation(OneToMany.class), "fetch"); + Fetch fetch = property.findAnnotation(Fetch.class); + if (null != fetch) { + this.fetchMode = fetch.value(); + } + else { + this.fetchMode = FetchMode.SELECT; // default + } + + this.targetModel = mappingContext.getRequiredModel(property.getActualType()); + + JoinColumns joinColumnsAnn = property.findAnnotation(JoinColumns.class); + if (null != joinColumnsAnn && joinColumnsAnn.value().length > 0) { + for (javax.persistence.JoinColumn joinColumnAnn : joinColumnsAnn.value()) { + this.joinColumns.add(this.processJoinColumn(this.targetModel, joinColumnAnn.name(), + joinColumnAnn.referencedColumnName())); + } + } + javax.persistence.JoinColumn joinColumnAnn = property.findAnnotation(javax.persistence.JoinColumn.class); + if (null != joinColumnAnn) { + this.joinColumns.add(this.processJoinColumn(this.targetModel, joinColumnAnn.name(), + joinColumnAnn.referencedColumnName())); + } + + if (this.joinColumns.isEmpty()) { + this.joinColumns.add(this.processJoinColumn(this.targetModel, null, null)); + } + + } + + private JoinColumn processJoinColumn(Model targetModel, String name, String referencedColumnName) { + PrimaryKey primaryKey = targetModel.getPrimaryKey(); + if (StringUtils.isEmpty(referencedColumnName) && !(primaryKey instanceof SinglePrimaryKey)) { + throw new MappingException("Could not find referenced column name for: " + targetModel.getAlias()); + } + referencedColumnName = StringUtils.hasText(referencedColumnName) ? referencedColumnName + : primaryKey.getColumns().iterator().next().getName().getCanonicalName(); + Column referencedColumn = targetModel.findColumn(referencedColumnName); + if (null == referencedColumn) { + throw new MappingException("Could not find referenced column by " + referencedColumnName); + } + + Column foreign = new Column(targetModel, referencedColumn.getProperty()); + foreign.setName(referencedColumn.getName()); + foreign.setJavaType(referencedColumn.getJavaType()); + foreign.setJdbcType(referencedColumn.getJdbcType()); + foreign.setTypeHandler(referencedColumn.getTypeHandler()); + + Column local = new Column(targetModel, referencedColumn.getProperty()); + local.setName(Identifier.toIdentifier(StringUtils.hasText(name) ? name + : targetModel.getTable().getName().getText() + '_' + foreign.getName().getText())); + local.setJavaType(foreign.getJavaType()); + local.setJdbcType(foreign.getJdbcType()); + local.setTypeHandler(foreign.getTypeHandler()); + return new JoinColumn(local, foreign); + } + + public MybatisPersistentProperty getProperty() { + return this.property; + } + + public String getFetchType() { + if (null == this.fetchType) { + return null; + } + return this.fetchType.name().toLowerCase(); + } + + public FetchMode getFetchMode() { + return this.fetchMode; + } + + public List getJoinColumns() { + return this.joinColumns; + } + + public Model getTargetModel() { + return this.targetModel; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToOneAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToOneAssociation.java new file mode 100644 index 0000000000000000000000000000000000000000..e5849d03f130f5846166f3b1b40012de925009ce --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToOneAssociation.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.lang.annotation.Annotation; + +import javax.persistence.OneToOne; + +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class OneToOneAssociation extends ManyToOneAssociation { + + private static final long serialVersionUID = 240806944716674713L; + + public OneToOneAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property, + String alias) { + super(mappingContext, owner, property, alias); + } + + @Override + protected Class getAnnotation() { + return OneToOne.class; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/PrimaryKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/PrimaryKey.java new file mode 100644 index 0000000000000000000000000000000000000000..229959e400f5e3b3bf0ae5cee5b9eb30a74111c5 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/PrimaryKey.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.Collection; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public interface PrimaryKey extends Component { + + /** + * Default sequence name. + */ + String DEFAULT_SEQUENCE_NAME = "seq_spring_data_mybatis"; + + boolean isComposited(); + + Collection getColumns(); + + Class getType(); + + Column findColumn(String name); + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/SinglePrimaryKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/SinglePrimaryKey.java new file mode 100644 index 0000000000000000000000000000000000000000..c28a879431179b30b43239672a46aca0812b5922 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/SinglePrimaryKey.java @@ -0,0 +1,151 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.SequenceGenerator; +import javax.persistence.SequenceGenerators; + +import org.springframework.data.mybatis.dialect.Dialect; +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; +import org.springframework.util.StringUtils; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class SinglePrimaryKey implements PrimaryKey { + + private final Column column; + + private final Model model; + + private final MybatisPersistentProperty property; + + private boolean generatedKeys; + + private String keySql; + + private String executeOrder; + + public SinglePrimaryKey(Model model, MybatisPersistentProperty property) { + this.model = model; + this.property = property; + + this.column = new Column(model, property); + + this.processGeneratedPrimaryKey(); + + } + + private void processGeneratedPrimaryKey() { + this.generatedKeys = this.property.isAnnotationPresent(GeneratedValue.class); + if (!this.generatedKeys) { + return; + } + + GeneratedValue gv = this.property.findAnnotation(GeneratedValue.class); + Dialect dialect = this.model.getMappingContext().getDialect(); + if (gv.strategy() == GenerationType.IDENTITY || (gv.strategy() == GenerationType.AUTO + && "identity".equals(dialect.getNativeIdentifierGeneratorStrategy()))) { + // identity + this.keySql = dialect.getIdentityColumnSupport().getIdentitySelectString(this.model.getTable().toString(), + this.column.getName().getCanonicalName(), this.column.getJdbcType().TYPE_CODE); + this.executeOrder = "AFTER"; + } + else if (gv.strategy() == GenerationType.SEQUENCE || (gv.strategy() == GenerationType.AUTO + && "sequence".equals(dialect.getNativeIdentifierGeneratorStrategy()))) { + String sequenceName = DEFAULT_SEQUENCE_NAME; + if (StringUtils.hasText(gv.generator())) { + // search sequence generator + Map sequenceGenerators = new HashMap<>(); + SequenceGenerators sequenceGeneratorsAnn = this.property + .findPropertyOrOwnerAnnotation(SequenceGenerators.class); + if (null != sequenceGeneratorsAnn && sequenceGeneratorsAnn.value().length > 0) { + sequenceGenerators.putAll(Stream.of(sequenceGeneratorsAnn.value()) + .filter(sg -> StringUtils.hasText(sg.sequenceName())) + .collect(Collectors.toMap(SequenceGenerator::name, SequenceGenerator::sequenceName))); + } + SequenceGenerator sg = this.property.findPropertyOrOwnerAnnotation(SequenceGenerator.class); + if (null != sg && StringUtils.hasText(sg.sequenceName())) { + sequenceGenerators.put(sg.name(), sg.sequenceName()); + } + + String sn = sequenceGenerators.get(gv.generator()); + if (StringUtils.hasText(sn)) { + sequenceName = sn; + } + } + this.keySql = dialect.getSequenceNextValString(sequenceName); + this.executeOrder = "BEFORE"; + } + else { + throw new UnsupportedOperationException("unsupported generated value id strategy: " + gv.strategy()); + } + } + + @Override + public boolean isComposited() { + return false; + } + + @Override + public Collection getColumns() { + return Arrays.asList(this.column); + } + + @Override + public Class getType() { + return this.property.getType(); + } + + @Override + public Column findColumn(String name) { + return name.equals(this.column.getName().getCanonicalName()) ? this.column : null; + } + + @Override + public Model getModel() { + return this.model; + } + + public boolean isGeneratedKeys() { + return this.generatedKeys; + } + + public String getKeySql() { + return this.keySql; + } + + public String getExecuteOrder() { + return this.executeOrder; + } + + public boolean excludeInsertId() { + return this.generatedKeys && !"BEFORE".equals(this.executeOrder); + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java index 1dc275fa2611a5e50b303b4d43dbc435febc7464..6e2046b2bbe3da6b4f449fb6aaa0b5308a143249 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java @@ -15,23 +15,25 @@ */ package org.springframework.data.mybatis.mapping.model; +import java.io.Serializable; + import lombok.Getter; +import lombok.experimental.Accessors; /** - * Table model. + * . * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.2 */ -public class Table { +@Getter +@Accessors(chain = true) +public class Table implements Serializable { - @Getter private Identifier schema; - @Getter private Identifier catalog; - @Getter private Identifier name; public Table(String schema, String catalog, String name) { @@ -44,7 +46,8 @@ public class Table { this.name = Identifier.toIdentifier(name); } - public String getFullName() { + @Override + public String toString() { return ((null != this.schema) ? (this.schema.getCanonicalName() + '.') : "") + // ((null != this.catalog) ? (this.catalog.getCanonicalName() + '.') : "") + // this.name.getCanonicalName(); diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/VersionColumn.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/VersionColumn.java new file mode 100644 index 0000000000000000000000000000000000000000..fe69e95d7fff085c7df0e386d03ec483b855c861 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/VersionColumn.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-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.mybatis.mapping.model; + +import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class VersionColumn extends Column { + + private static final long serialVersionUID = 8187675205177183423L; + + public VersionColumn(Model model, MybatisPersistentProperty property) { + super(model, property); + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/AbstractMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/AbstractMybatisPrecompiler.java new file mode 100644 index 0000000000000000000000000000000000000000..4fac08b1f699167c73177e517e63f27e026223e3 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/AbstractMybatisPrecompiler.java @@ -0,0 +1,199 @@ +/* + * Copyright 2012-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.mybatis.precompiler; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Mustache.InvertibleLambda; +import com.samskivert.mustache.Mustache.Lambda; +import com.samskivert.mustache.Template.Fragment; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.builder.xml.XMLMapperBuilder; +import org.apache.ibatis.executor.ErrorContext; +import org.apache.ibatis.session.Configuration; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.mapping.MappingException; +import org.springframework.data.mybatis.dialect.pagination.SQLServer2005LimitHandler; +import org.springframework.data.mybatis.dialect.pagination.SQLServer2012LimitHandler; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.model.Identifier; +import org.springframework.data.mybatis.mapping.model.Model; +import org.springframework.data.mybatis.repository.query.DefaultCollector; +import org.springframework.data.mybatis.repository.support.SqlSessionRepositorySupport; +import org.springframework.util.CollectionUtils; + +/** + * Abstract mybatis mapper precompiler. + * + * @author JARVIS SONG + */ +@Slf4j +abstract class AbstractMybatisPrecompiler implements MybatisPrecompiler { + + protected static final String SCOPE_STATEMENT_NAME = "statementName"; + + protected static final String SCOPE_RESULT_MAP = "resultMap"; + + protected final MybatisMappingContext mappingContext; + + protected final Model domain; + + protected final Mustache.Compiler mustache; + + protected AbstractMybatisPrecompiler(MybatisMappingContext mappingContext, Model domain) { + this.mappingContext = mappingContext; + this.domain = domain; + this.mustache = Mustache.compiler().withLoader(name -> { + InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(this.getTemplatePath(name)); + return new InputStreamReader(inputStream, StandardCharsets.UTF_8); + }).escapeHTML(false).withCollector(new DefaultCollector()); + } + + @Override + public void compile() { + this.compileMapper(this.domain.getMappingEntity().getName(), this.prepareStatements()); + } + + protected abstract Collection prepareStatements(); + + protected String render(String name, Map scopes) { + if (null == scopes) { + scopes = new HashMap<>(); + } + scopes.put("domain", this.domain); + scopes.put("quote", (Lambda) (frag, out) -> out.write(this.quote(frag.execute()))); + scopes.put("testNotNull", this.lambdaTestNotNull()); + scopes.put("escapeQuotes", (Lambda) (frag, out) -> out.write(frag.execute().replace("\"", "\\\""))); + scopes.put("lowercaseFunction", this.mappingContext.getDialect().getLowercaseFunction()); + scopes.put("SQLServer2005", + this.mappingContext.getDialect().getLimitHandler().getClass() == SQLServer2005LimitHandler.class); + scopes.put("SQLServer2012", + this.mappingContext.getDialect().getLimitHandler().getClass() == SQLServer2012LimitHandler.class); + try (InputStream is = new ClassPathResource(this.getTemplatePath(name)).getInputStream(); + InputStreamReader source = new InputStreamReader(is, StandardCharsets.UTF_8)) { + return this.mustache.compile(source).execute(scopes); + } + catch (IOException ex) { + throw new MappingException("Could not render the statement: " + name, ex); + } + } + + protected void compileMapper(String namespace, Collection statements) { + this.compileMapper(this.getResource("basic", namespace), namespace, statements); + } + + protected void compileMapper(String resource, String namespace, Collection statements) { + if (CollectionUtils.isEmpty(statements)) { + return; + } + Map scopes = new HashMap<>(); + scopes.put("namespace", namespace); + scopes.put("statements", statements); + scopes.put("resource", resource + this.getResourceSuffix()); + String mapper = this.render("Mapper", scopes); + + if (log.isDebugEnabled()) { + log.debug(mapper); + } + Configuration configuration = this.mappingContext.getSqlSessionTemplate().getConfiguration(); + try (InputStream is = new ByteArrayInputStream(mapper.getBytes(StandardCharsets.UTF_8))) { + XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(is, configuration, + resource + this.getResourceSuffix(), configuration.getSqlFragments()); + xmlMapperBuilder.parse(); + } + catch (Exception ex) { + throw new MappingException(ex.getMessage(), ex); + } + finally { + ErrorContext.instance().reset(); + } + } + + protected boolean checkSqlFragment(String name) { + return this.mappingContext.getSqlSessionTemplate().getConfiguration().getSqlFragments() + .containsKey(this.domain.getMappingEntity().getName() + SqlSessionRepositorySupport.DOT + name); + } + + protected boolean checkResultMap(String name) { + return this.mappingContext.getSqlSessionTemplate().getConfiguration() + .hasResultMap(this.domain.getMappingEntity().getName() + SqlSessionRepositorySupport.DOT + name); + } + + protected boolean checkStatement(String name) { + return this.checkStatement(this.domain.getMappingEntity().getName(), name); + } + + protected boolean checkStatement(String namespace, String name) { + return this.mappingContext.getSqlSessionTemplate().getConfiguration() + .hasStatement(namespace + SqlSessionRepositorySupport.DOT + name, false); + } + + protected String getResource(String dir, String namespace) { + return dir + '/' + namespace.replace('.', '/'); + } + + protected String getResourceSuffix() { + return ".xml"; + } + + protected String getTemplatePath(String name) { + return "org/springframework/data/mybatis/repository/query/template/" + name + ".mustache"; + } + + protected String quote(String name) { + return Identifier.toIdentifier(name, true).render(this.mappingContext.getDialect()); + } + + Mustache.InvertibleLambda lambdaTestNotNull() { + return new InvertibleLambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + out.write(this.testClause(frag.execute().trim(), true, true)); + } + + @Override + public void executeInverse(Fragment frag, Writer out) throws IOException { + out.write(this.testClause(frag.execute().trim(), false, false)); + } + + protected String testClause(String propertyName, boolean and, boolean not) { + String[] parts = propertyName.split("\\."); + String[] conditions = new String[parts.length]; + String prev = null; + for (int i = 0; i < parts.length; i++) { + conditions[i] = ((null != prev) ? (prev + ".") : "") + parts[i]; + prev = conditions[i]; + } + String test = Stream.of(conditions).map(c -> c.trim() + (not ? " !" : " =") + "= null") + .collect(Collectors.joining(and ? " and " : " or ")); + return test; + } + }; + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisPrecompiler.java new file mode 100644 index 0000000000000000000000000000000000000000..1f6515f39b258507627c1b4833b19c7d7e2423fd --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisPrecompiler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-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.mybatis.precompiler; + +/** + * Spring data mybatis mapper precompiler. + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public interface MybatisPrecompiler { + + void compile(); + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryPrepareProcessor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisQueryPrepareProcessor.java similarity index 65% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryPrepareProcessor.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisQueryPrepareProcessor.java index 575f3595d7b11ab6f5da9212e7ee2a09887f59f7..ee76df31479547467ce4b8bd18605bcb9c7a26c4 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryPrepareProcessor.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisQueryPrepareProcessor.java @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mybatis.repository.query; +package org.springframework.data.mybatis.precompiler; -import org.apache.ibatis.session.Configuration; - -import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.repository.query.PartTreeMybatisQuery; +import org.springframework.data.mybatis.repository.query.SimpleMybatisQuery; import org.springframework.data.repository.core.support.QueryCreationListener; import org.springframework.data.repository.query.RepositoryQuery; @@ -26,41 +25,29 @@ import org.springframework.data.repository.query.RepositoryQuery; * Prepare mybatis mapper statement when a query created. * * @author JARVIS SONG - * @since 2.0.0 + * @since 2.0.1 */ public class MybatisQueryPrepareProcessor implements QueryCreationListener { private final MybatisMappingContext mappingContext; - private final Configuration configuration; - - private final Dialect dialect; + public MybatisQueryPrepareProcessor(MybatisMappingContext mappingContext) { - public MybatisQueryPrepareProcessor(MybatisMappingContext mappingContext, Configuration configuration, - Dialect dialect) { this.mappingContext = mappingContext; - this.configuration = configuration; - this.dialect = dialect; } @Override public void onCreation(RepositoryQuery query) { if (query instanceof SimpleMybatisQuery) { - new SimpleMybatisQueryPrecompiler(this.mappingContext, this.configuration, this.dialect, - (SimpleMybatisQuery) query).precompile(); - return; - } - if (query instanceof PartTreeMybatisQuery) { - new PartTreeMyBatisQueryPrecompiler(this.mappingContext, this.configuration, this.dialect, - (PartTreeMybatisQuery) query).precompile(); + new SimpleMybatisQueryPrecompiler(this.mappingContext, (SimpleMybatisQuery) query).compile(); return; } - if (query instanceof StoredProcedureMybatisQuery) { + if (query instanceof PartTreeMybatisQuery) { + new PartTreeMybatisQueryPrecompiler(this.mappingContext, (PartTreeMybatisQuery) query).compile(); return; } - } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/PartTreeMyBatisQueryPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/PartTreeMybatisQueryPrecompiler.java similarity index 54% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/PartTreeMyBatisQueryPrecompiler.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/PartTreeMybatisQueryPrecompiler.java index 54c4e40ae8d7ed8a4a027b872bb0795994792052..fea596181ff9526c91af9f945a53dec13e8d8520 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/PartTreeMyBatisQueryPrecompiler.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/PartTreeMybatisQueryPrecompiler.java @@ -13,34 +13,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mybatis.repository.query; +package org.springframework.data.mybatis.precompiler; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.persistence.EmbeddedId; import com.samskivert.mustache.Mustache.Lambda; import lombok.Getter; -import org.apache.ibatis.session.Configuration; -import org.springframework.data.mybatis.dialect.Dialect; +import org.springframework.data.mapping.MappingException; +import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mybatis.dialect.pagination.RowSelection; -import org.springframework.data.mybatis.dialect.pagination.SQLServer2005LimitHandler; -import org.springframework.data.mybatis.dialect.pagination.SQLServer2012LimitHandler; import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; -import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; import org.springframework.data.mybatis.mapping.model.Column; +import org.springframework.data.mybatis.repository.query.MybatisParameters; import org.springframework.data.mybatis.repository.query.MybatisParameters.MybatisParameter; +import org.springframework.data.mybatis.repository.query.MybatisQueryMethod; +import org.springframework.data.mybatis.repository.query.PartTreeMybatisQuery; import org.springframework.data.mybatis.repository.support.ResidentStatementName; import org.springframework.data.repository.query.parser.Part; import org.springframework.data.repository.query.parser.Part.IgnoreCaseType; import org.springframework.data.repository.query.parser.PartTree; +import org.springframework.data.util.Streamable; import org.springframework.util.StringUtils; /** @@ -48,129 +49,109 @@ import org.springframework.util.StringUtils; * * @author JARVIS SONG */ -class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { +class PartTreeMybatisQueryPrecompiler extends AbstractMybatisPrecompiler { private final PartTreeMybatisQuery query; - private AtomicInteger argumentCounter = new AtomicInteger(0); - - PartTreeMyBatisQueryPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect, - PartTreeMybatisQuery query) { - super(mappingContext, configuration, dialect, query); + private final AtomicInteger argumentCounter = new AtomicInteger(0); + PartTreeMybatisQueryPrecompiler(MybatisMappingContext mappingContext, PartTreeMybatisQuery query) { + super(mappingContext, + mappingContext.getRequiredModel(query.getQueryMethod().getEntityInformation().getJavaType())); this.query = query; } @Override - protected String mainQueryString() { - return null; + protected Collection prepareStatements() { + + String statement = this.doPrepareStatement(); + return StringUtils.isEmpty(statement) ? Collections.emptyList() : Collections.singletonList(statement); } @Override - protected String doPrecompile() { + protected String getResource(String dir, String namespace) { + return "tree/" + this.query.getStatementId().replace('.', '/'); + } + + private String doPrepareStatement() { PartTree tree = this.query.getTree(); MybatisQueryMethod method = this.query.getQueryMethod(); - if (tree.isDelete()) { - return this.addDeleteStatement(tree, method); + return this.deleteStatement(); } if (tree.isCountProjection()) { - return this.addCountStatement(); + return this.countProjectionStatement(); } if (tree.isExistsProjection()) { - return this.addExistsStatement(); + return this.existsProjectionStatement(); } if (method.isPageQuery()) { - return this.addPageStatement(true); + return this.pageQueryStatement(); } if (method.isSliceQuery()) { - return this.addPageStatement(false); + return this.sliceQueryStatement(); } if (method.isCollectionQuery() || method.isStreamQuery()) { - return this.addCollectionStatement(); + return this.collectionQueryStatement(); } - if (method.isQueryForEntity()) { - return this.buildSelectStatementSegment(this.query.getStatementName(), false); + return this.selectQueryStatement(); } - return null; } - private String addDeleteStatement(PartTree tree, MybatisQueryMethod method) { - + private String deleteStatement() { Map scopes = new HashMap<>(); - scopes.put("statementName", this.query.getStatementName()); - scopes.put("table", this.getTableName()); - scopes.put("tree", this.convert(tree)); - - if (method.isCollectionQuery()) { - // need to return the deleted entities collection - return this.render("PartTreeDelete", scopes) + this.buildSelectStatementSegment( - ResidentStatementName.QUERY_PREFIX + this.query.getStatementName(), false); + scopes.put("tree", this.convert(this.query.getTree(), false)); + if (this.query.getQueryMethod().isCollectionQuery()) { + return this.render("PartTreeDelete", scopes) + this.render("PartTreeInnerSelect", this + .innerSelectQueryScopes(ResidentStatementName.QUERY_PREFIX + this.query.getStatementName(), false)); } - return this.render("PartTreeDelete", scopes); - } - private String addCountStatement() { - return this.buildCountStatementSegment(this.query.getStatementName()); + private String countProjectionStatement() { + return this.render("PartTreeInnerCount", this.innerCountQueryScopes(this.query.getStatementName())); } - private String addExistsStatement() { - return this.buildCountStatementSegment(this.query.getStatementName()); + private String existsProjectionStatement() { + return this.countProjectionStatement(); } - private String addPageStatement(boolean includeCount) { - String sql = this.buildSelectStatementSegment(this.query.getStatementName(), true); - sql += this.buildSelectStatementSegment(ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(), - false); - if (includeCount) { - String count = this.buildCountStatementSegment(this.query.getCountStatementName()); - return sql + count; - } - return sql; + private String pageQueryStatement() { + return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), true)) + + this.render("PartTreeInnerSelect", + this.innerSelectQueryScopes( + ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(), false)) + + this.render("PartTreeInnerCount", this.innerCountQueryScopes(this.query.getCountStatementName())); } - private String addCollectionStatement() { - return this.buildSelectStatementSegment(this.query.getStatementName(), - this.query.getQueryMethod().getParameters().hasPageableParameter()); + private String sliceQueryStatement() { + return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), true)) + + this.render("PartTreeInnerSelect", this.innerSelectQueryScopes( + ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(), false)); } - private String buildCountStatementSegment(String statementName) { - PartTree tree = this.query.getTree(); - Map scopes = new HashMap<>(); - scopes.put("statementName", statementName); - scopes.put("table", this.getTableName()); - scopes.put("tree", this.convert(tree)); - scopes.put("columns", tree.isLimiting() ? "1" : "COUNT(*)"); - scopes.put("limiting", tree.isLimiting()); - if (tree.isLimiting()) { - RowSelection selection = new RowSelection(0, tree.getMaxResults()); - scopes.put("limitHandler", (Lambda) (frag, out) -> { - out.write(this.dialect.getLimitHandler().processSql(frag.execute(), selection)); - }); - scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class); - scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class); - } + private String collectionQueryStatement() { + return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), + this.query.getQueryMethod().getParameters().hasPageableParameter())); + } - return this.render("PartTreeCount", scopes); + private String selectQueryStatement() { + return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), false)); } - private String buildSelectStatementSegment(String statementName, boolean pageable) { + private Map innerSelectQueryScopes(String statementName, boolean pageable) { PartTree tree = this.query.getTree(); MybatisQueryMethod method = this.query.getQueryMethod(); Map scopes = new HashMap<>(); - scopes.put("statementName", statementName); - scopes.put("table", this.getTableName()); - scopes.put("tree", this.convert(tree)); + scopes.put("innerStatementName", statementName); - String columns = "*"; + String columns = ""; if (StringUtils.hasText(method.getSelectColumns())) { - String[] selectColumns = method.getSelectColumns().split(","); - columns = Stream.of(selectColumns).map(String::trim).filter(StringUtils::hasText).map( - sc -> this.persistentEntity.getRequiredPersistentProperty(sc).getColumn().getName().render(dialect)) + String[] selectedColumns = method.getSelectColumns().split(","); + columns = Arrays.stream(selectedColumns).map(String::trim).filter(StringUtils::hasText).map( + sc -> this.domain.findColumnByPropertyName(sc).getName().render(this.mappingContext.getDialect())) .collect(Collectors.joining(",")); } scopes.put("columns", columns); @@ -186,7 +167,7 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { } else if (null != method.getResultType()) { scopes.put("isResultMap", false); - if (method.getResultType() == Void.class) { + if (method.getResultType() == Void.class || method.getResultType() == void.class) { scopes.put("result", method.getActualResultType()); } else { @@ -209,46 +190,78 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { if (null == selection) { selection = new RowSelection(true); } - RowSelection rowSelection = selection; - scopes.put("limitHandler", (Lambda) (frag, out) -> { - out.write(this.dialect.getLimitHandler().processSql(frag.execute(), rowSelection)); - }); - scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class); - scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class); + scopes.put("limitHandler", (Lambda) (frag, out) -> out.write( + this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), rowSelection))); } - scopes.put("pageable", pageable); - return render("PartTreeSelect", scopes); + return scopes; } - public List convert(PartTree tree) { - this.argumentCounter.set(0); - return tree.stream().map(orPart -> new OrPart(orPart, this.persistentEntity, this.mappingContext, - this.argumentCounter, this.query.getQueryMethod(), this.dialect)).collect(Collectors.toList()); + private Map innerCountQueryScopes(String statementName) { + PartTree tree = this.query.getTree(); + MybatisQueryMethod method = this.query.getQueryMethod(); + Map scopes = new HashMap<>(); + scopes.put("innerStatementName", statementName); + scopes.put("limiting", tree.isLimiting()); + scopes.put("columns", tree.isLimiting() ? "1" : "COUNT(*)"); + if (tree.isLimiting()) { + RowSelection selection = new RowSelection(0, tree.getMaxResults()); + scopes.put("limitHandler", (Lambda) (frag, out) -> out + .write(this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), selection))); + } + return scopes; } @Override - protected String getResourceSuffix() { - return "_tree_" + this.query.getStatementName() + super.getResourceSuffix(); + protected String render(String name, Map scopes) { + if (null == scopes) { + scopes = new HashMap<>(); + } + scopes.putIfAbsent(SCOPE_STATEMENT_NAME, this.query.getStatementName()); + scopes.putIfAbsent("tree", this.convert(this.query.getTree(), true)); + return super.render(name, scopes); } - @Getter - public static class OrPart { + private Tree convert(PartTree tree, boolean includeAlias) { + this.argumentCounter.set(0); // reset the argument counter + return new Tree(tree, includeAlias); + } + + public class Tree implements Streamable { + + private final List orParts; - private List parts; + Tree(PartTree tree, boolean includeAlias) { + this.orParts = tree.stream().map(orPart -> new OrPart(orPart, includeAlias)).collect(Collectors.toList()); + } + + @Override + public Iterator iterator() { + return this.orParts.iterator(); + } + + } + + public class OrPart implements Streamable { - OrPart(PartTree.OrPart or, MybatisPersistentEntity persistentEntity, MybatisMappingContext mappingContext, - AtomicInteger argumentCounter, MybatisQueryMethod method, Dialect dialect) { - this.parts = or.stream() - .map(part -> new AndPart(part, persistentEntity, mappingContext, argumentCounter, method, dialect)) - .collect(Collectors.toList()); + private final List andParts; + + OrPart(PartTree.OrPart orPart, boolean includeAlias) { + this.andParts = orPart.stream().map(part -> new AndPart(part, includeAlias)).collect(Collectors.toList()); + } + + @Override + public Iterator iterator() { + return this.andParts.iterator(); } } @Getter - public static class AndPart { + public class AndPart { + + private final boolean includeAlias; private final Column column; @@ -256,8 +269,6 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { private boolean ignoreCase; - private String lowercaseFunction; - private boolean opBetween; private boolean opNotNull; @@ -312,29 +323,25 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { private boolean arrayParameter; - AndPart(Part part, MybatisPersistentEntity persistentEntity, MybatisMappingContext mappingContext, - AtomicInteger argumentCounter, MybatisQueryMethod method, Dialect dialect) { - MybatisPersistentProperty persistentProperty = persistentEntity - .getRequiredPersistentProperty(part.getProperty().getSegment()); - if (persistentProperty.isAnnotationPresent(EmbeddedId.class) || persistentProperty.isEmbeddable()) { - MybatisPersistentEntity leafEntity = mappingContext - .getRequiredPersistentEntity(part.getProperty().getLeafProperty().getOwningType()); - persistentProperty = leafEntity - .getPersistentProperty(part.getProperty().getLeafProperty().getSegment()); + AndPart(Part part, boolean includeAlias) { + this.includeAlias = includeAlias; + PropertyPath propertyPath = part.getProperty(); + this.column = PartTreeMybatisQueryPrecompiler.this.domain.findColumn(propertyPath); + if (null == this.column) { + throw new MappingException("Could not find column for " + propertyPath); } + if (part.shouldIgnoreCase() == IgnoreCaseType.ALWAYS - || (part.shouldIgnoreCase() == IgnoreCaseType.WHEN_POSSIBLE && null != persistentProperty - && CharSequence.class.isAssignableFrom(persistentProperty.getType()))) { + || (part.shouldIgnoreCase() == IgnoreCaseType.WHEN_POSSIBLE && this.column.isString())) { this.ignoreCase = true; - this.lowercaseFunction = dialect.getLowercaseFunction(); } - this.column = persistentProperty.getColumn(); this.arguments = new String[part.getNumberOfArguments()]; if (part.getNumberOfArguments() > 0) { - MybatisParameters parameters = method.getParameters(); + MybatisParameters parameters = PartTreeMybatisQueryPrecompiler.this.query.getQueryMethod() + .getParameters(); for (int i = 0; i < part.getNumberOfArguments(); i++) { - int counter = argumentCounter.getAndIncrement(); + int counter = PartTreeMybatisQueryPrecompiler.this.argumentCounter.getAndIncrement(); MybatisParameter bindableParameter = parameters.getBindableParameter(counter); this.arguments[i] = bindableParameter.getName().orElse("__p" + (bindableParameter.getIndex() + 1)); this.arrayParameter = bindableParameter.getType().isArray(); diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisPrecompiler.java new file mode 100644 index 0000000000000000000000000000000000000000..73ae2aff9f32fbd8017a62b0495f1bf67cd35d2e --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisPrecompiler.java @@ -0,0 +1,473 @@ +/* + * Copyright 2012-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.mybatis.precompiler; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.samskivert.mustache.Mustache.Lambda; + +import org.springframework.data.mybatis.dialect.pagination.RowSelection; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.mapping.model.ManyToManyAssociation; +import org.springframework.data.mybatis.mapping.model.ManyToOneAssociation; +import org.springframework.data.mybatis.mapping.model.Model; +import org.springframework.data.mybatis.mapping.model.OneToManyAssociation; +import org.springframework.data.mybatis.repository.support.ResidentStatementName; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +/** + * Simple mybatis mapper precompiler. + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class SimpleMybatisPrecompiler extends AbstractMybatisPrecompiler { + + public SimpleMybatisPrecompiler(MybatisMappingContext mappingContext, Model domain) { + super(mappingContext, domain); + } + + @Override + protected Collection prepareStatements() { + List statements = new ArrayList<>(); + statements.add(this.columnListFragment()); + statements.add(this.fromFragment()); + statements.add(this.selectFragment()); + statements.add(this.whereClauseByIdFragment()); + statements.add(this.whereClauseByIdsFragment()); + statements.add(this.standardSortFragment()); + statements.add(this.queryByExampleWhereClauseFragment()); + + statements.add(this.resultMap()); + + statements.add(this.insertStatement()); + statements.add(this.insertSelectiveStatement()); + statements.add(this.updateStatement()); + statements.add(this.updateByIdStatement()); + statements.add(this.updateSelectiveStatement()); + statements.add(this.updateSelectiveByIdStatement()); + statements.add(this.deleteByIdStatement()); + statements.add(this.deleteByIdsStatement()); + statements.add(this.deleteAllStatement()); + statements.add(this.getByIdStatement()); + statements.add(this.findStatement()); + statements.add(this.findByPageStatement()); + statements.add(this.countAllStatement()); + statements.add(this.countStatement()); + statements.add(this.queryByExampleStatement()); + statements.add(this.queryByExampleForPageStatement()); + statements.add(this.countByExampleStatement()); + + this.resultMapOneToManySelectStatement(); + this.resultMapManyToManySelectStatement(); + this.associativeTableStatement(); + + // Basic + // statements.add(this.basicColumnListFragment()); + // statements.add(this.basicResultMap()); + + return statements.stream().filter(StringUtils::hasText).collect(Collectors.toList()); + } + + private void resultMapOneToManySelectStatement() { + if (CollectionUtils.isEmpty(this.domain.getOneToManyAssociations())) { + return; + } + this.domain.getOneToManyAssociations().forEach(ass -> { + String statementName = "__association_" + this.domain.getTable() + '_' + + ((OneToManyAssociation) ass).getProperty().getName(); + if (this.checkStatement(ass.getMappingEntity().getName(), statementName)) { + return; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, statementName); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + scopes.put("ass", ass); + String ns = ass.getMappingEntity().getName(); + this.compileMapper("select/" + ns.replace('.', '/') + "/" + statementName, ns, + Collections.singletonList(this.render("ResultMapOneToManySelect", scopes))); + }); + } + + private void resultMapManyToManySelectStatement() { + if (CollectionUtils.isEmpty(this.domain.getManyToManyAssociations())) { + return; + } + this.domain.getManyToManyAssociations().forEach(ass -> { + String statementName = "__association_" + this.domain.getTable() + '_' + + ((ManyToManyAssociation) ass).getProperty().getName(); + String ns = ass.getMappingEntity().getName(); + if (this.checkStatement(ns, statementName)) { + return; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, statementName); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + scopes.put("ass", ass); + this.compileMapper("select/" + ns.replace('.', '/') + "/" + statementName, ns, + Collections.singletonList(this.render("ResultMapManyToManySelect", scopes))); + }); + } + + private void associativeTableStatement() { + if (CollectionUtils.isEmpty(this.domain.getManyToManyAssociations())) { + return; + } + this.domain.getManyToManyAssociations().forEach(ass -> { + String namespace = "associative." + ((ManyToManyAssociation) ass).getJoinTable().getTable().toString(); + if (this.checkStatement(namespace, ResidentStatementName.INSERT)) { + return; + } + Map scopes = new HashMap<>(); + scopes.put("ass", ass); + + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.INSERT); + this.compileMapper("associative/" + namespace.replace('.', '/') + "/insert", namespace, + Collections.singletonList(this.render("AssociativeInsert", scopes))); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE); + this.compileMapper("associative/" + namespace.replace('.', '/') + "/update", namespace, + Collections.singletonList(this.render("AssociativeUpdate", scopes))); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE); + this.compileMapper("associative/" + namespace.replace('.', '/') + "/delete", namespace, + Collections.singletonList(this.render("AssociativeDelete", scopes))); + }); + + } + + private String basicColumnListFragment() { + if (this.checkSqlFragment(ResidentStatementName.BASIC_COLUMN_LIST)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.BASIC_COLUMN_LIST); + return this.render("BasicColumnList", scopes); + } + + private String allColumnListFragment() { + if (this.checkSqlFragment(ResidentStatementName.ALL_COLUMN_LIST)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.ALL_COLUMN_LIST); + return this.render("AllColumnList", scopes); + } + + private String columnListFragment() { + if (this.checkSqlFragment(ResidentStatementName.COLUMN_LIST)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COLUMN_LIST); + return this.render("ColumnList", scopes); + } + + private String fromFragment() { + if (this.checkSqlFragment(ResidentStatementName.FROM)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.FROM); + return this.render("From", scopes); + } + + private String selectFragment() { + if (this.checkSqlFragment(ResidentStatementName.SELECT)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.SELECT); + return this.render("Select", scopes); + } + + private String whereClauseByIdFragment() { + if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_ID_CLAUSE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.WHERE_BY_ID_CLAUSE); + return this.render("WhereClauseById", scopes); + } + + private String whereClauseByIdsFragment() { + if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_IDS_CLAUSE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.WHERE_BY_IDS_CLAUSE); + return this.render("WhereClauseByIds", scopes); + } + + private String standardSortFragment() { + if (this.checkSqlFragment(ResidentStatementName.STANDARD_SORT)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.STANDARD_SORT); + return this.render("StandardSort", scopes); + } + + private String queryByExampleWhereClauseFragment() { + if (this.checkSqlFragment(ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE); + scopes.put("replaceDotToUnderline", (Lambda) (frag, out) -> out.write(frag.execute().trim().replace('.', '_'))); + + List columns = new LinkedList<>(); + if (null != this.domain.getPrimaryKey()) { + columns.addAll(this.domain.getPrimaryKey().getColumns()); + } + if (!CollectionUtils.isEmpty(this.domain.getNormalColumns())) { + columns.addAll(this.domain.getNormalColumns()); + } + if (!CollectionUtils.isEmpty(this.domain.getVersionColumns())) { + columns.addAll(this.domain.getVersionColumns()); + } + if (!CollectionUtils.isEmpty(this.domain.getEmbeddings())) { + this.domain.getEmbeddings().stream().forEach(embedding -> { + if (null != embedding.getPrimaryKey()) { + columns.addAll(embedding.getPrimaryKey().getColumns()); + } + if (!CollectionUtils.isEmpty(embedding.getNormalColumns())) { + columns.addAll(embedding.getNormalColumns()); + } + if (!CollectionUtils.isEmpty(embedding.getVersionColumns())) { + columns.addAll(embedding.getVersionColumns()); + } + }); + } + if (!CollectionUtils.isEmpty(this.domain.getManyToOneAssociations())) { + this.domain.getManyToOneAssociations().stream().forEach(association -> { + ManyToOneAssociation ass = (ManyToOneAssociation) association; + if (!ass.isLeftJoin()) { + return; + } + + if (null != ass.getPrimaryKey()) { + columns.addAll(ass.getPrimaryKey().getColumns()); + } + if (!CollectionUtils.isEmpty(ass.getNormalColumns())) { + columns.addAll(ass.getNormalColumns()); + } + if (!CollectionUtils.isEmpty(ass.getVersionColumns())) { + columns.addAll(ass.getVersionColumns()); + } + + }); + } + + scopes.put("combinedColumns", columns); + + return this.render("QueryByExampleWhereClause", scopes); + } + + private String basicResultMap() { + if (this.checkResultMap(ResidentStatementName.BASIC_RESULT_MAP)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.BASIC_RESULT_MAP); + return this.render("BasicResultMap", scopes); + } + + private String resultMap() { + if (this.checkResultMap(ResidentStatementName.RESULT_MAP)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.RESULT_MAP); + return this.render("ResultMap", scopes); + } + + private String insertStatement() { + if (this.checkStatement(ResidentStatementName.INSERT)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.INSERT); + return this.render("Insert", scopes); + } + + private String insertSelectiveStatement() { + if (this.checkStatement(ResidentStatementName.INSERT_SELECTIVE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.INSERT_SELECTIVE); + return this.render("InsertSelective", scopes); + } + + private String updateStatement() { + if (this.checkStatement(ResidentStatementName.UPDATE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE); + scopes.put("byId", false); + return this.render("Update", scopes); + } + + private String updateByIdStatement() { + if (this.checkStatement(ResidentStatementName.UPDATE_BY_ID)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE_BY_ID); + scopes.put("byId", true); + return this.render("Update", scopes); + } + + private String updateSelectiveStatement() { + if (this.checkStatement(ResidentStatementName.UPDATE_SELECTIVE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE_SELECTIVE); + scopes.put("byId", false); + return this.render("UpdateSelective", scopes); + } + + private String updateSelectiveByIdStatement() { + if (this.checkStatement(ResidentStatementName.UPDATE_SELECTIVE_BY_ID)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE_SELECTIVE_BY_ID); + scopes.put("byId", true); + return this.render("UpdateSelective", scopes); + } + + private String deleteByIdStatement() { + if (this.checkStatement(ResidentStatementName.DELETE_BY_ID)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE_BY_ID); + return this.render("DeleteById", scopes); + } + + private String deleteByIdsStatement() { + if (this.checkStatement(ResidentStatementName.DELETE_BY_IDS)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE_BY_IDS); + return this.render("DeleteByIds", scopes); + } + + private String deleteAllStatement() { + if (this.checkStatement(ResidentStatementName.DELETE_ALL)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE_ALL); + // FIXME: change to use truncate? + return this.render("DeleteAll", scopes); + } + + private String getByIdStatement() { + if (this.checkStatement(ResidentStatementName.GET_BY_ID)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.GET_BY_ID); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + return this.render("GetById", scopes); + } + + private String findStatement() { + if (this.checkStatement(ResidentStatementName.FIND)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.FIND); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + scopes.put("conditionQuery", ""); // TODO + return this.render("Find", scopes); + } + + private String findByPageStatement() { + if (this.checkStatement(ResidentStatementName.FIND_BY_PAGER)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.FIND_BY_PAGER); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + scopes.put("limitHandler", (Lambda) (frag, out) -> out.write( + this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), new RowSelection(true)))); + scopes.put("conditionQuery", ""); // TODO + return this.render("FindByPage", scopes); + } + + private String countAllStatement() { + if (this.checkStatement(ResidentStatementName.COUNT_ALL)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COUNT_ALL); + return this.render("CountAll", scopes); + } + + private String countStatement() { + if (this.checkStatement(ResidentStatementName.COUNT)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COUNT); + return this.render("Count", scopes); + } + + private String queryByExampleStatement() { + if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.QUERY_BY_EXAMPLE); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + return this.render("QueryByExample", scopes); + } + + private String queryByExampleForPageStatement() { + if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE); + scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP); + scopes.put("limitHandler", (Lambda) (frag, out) -> out.write( + this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), new RowSelection(true)))); + return this.render("QueryByExampleForPage", scopes); + } + + private String countByExampleStatement() { + if (this.checkStatement(ResidentStatementName.COUNT_QUERY_BY_EXAMPLE)) { + return null; + } + Map scopes = new HashMap<>(); + scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COUNT_QUERY_BY_EXAMPLE); + return this.render("CountQueryByExample", scopes); + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQueryPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisQueryPrecompiler.java similarity index 49% rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQueryPrecompiler.java rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisQueryPrecompiler.java index 1442e5f6b613358db1b30b5dd60023f53a604151..88ac73812b4d04c58b72346c99764a7f21f78fb7 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQueryPrecompiler.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisQueryPrecompiler.java @@ -13,22 +13,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mybatis.repository.query; +package org.springframework.data.mybatis.precompiler; import java.lang.reflect.Constructor; import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.ibatis.session.Configuration; +import com.samskivert.mustache.Mustache.Lambda; +import lombok.AllArgsConstructor; +import lombok.Data; import org.springframework.data.mapping.MappingException; -import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.dialect.pagination.RowSelection; import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.repository.query.DeclaredQuery; +import org.springframework.data.mybatis.repository.query.MybatisParameters; +import org.springframework.data.mybatis.repository.query.MybatisParameters.MybatisParameter; +import org.springframework.data.mybatis.repository.query.MybatisQueryMethod; +import org.springframework.data.mybatis.repository.query.QueryUtils; +import org.springframework.data.mybatis.repository.query.SimpleMybatisQuery; +import org.springframework.data.mybatis.repository.query.StringQuery; +import org.springframework.data.mybatis.repository.query.StringQuery.ParameterBinding; import org.springframework.data.mybatis.repository.support.ResidentParameterName; import org.springframework.data.mybatis.repository.support.ResidentStatementName; import org.springframework.util.ClassUtils; @@ -36,13 +50,11 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** - * Precompiler for {@link SimpleMybatisQuery}. + * . * * @author JARVIS SONG */ -class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { - - private final SimpleMybatisQuery query; +class SimpleMybatisQueryPrecompiler extends AbstractMybatisPrecompiler { private static Pattern patternIndex = Pattern.compile("[(\\d+)]"); @@ -50,38 +62,156 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { private static Pattern patternString = Pattern.compile("'.+'"); - SimpleMybatisQueryPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect, - SimpleMybatisQuery query) { + private static final Pattern SELECT_ALL_FROM = Pattern.compile("^\\s*select\\s+\\*\\s+from\\s+.*", + Pattern.CASE_INSENSITIVE); - super(mappingContext, configuration, dialect, query); + private final SimpleMybatisQuery query; + SimpleMybatisQueryPrecompiler(MybatisMappingContext mappingContext, SimpleMybatisQuery query) { + super(mappingContext, + mappingContext.getRequiredModel(query.getQueryMethod().getEntityInformation().getJavaType())); this.query = query; } @Override - protected String mainQueryString() { - return this.queryString(this.query.getQuery()); + protected Collection prepareStatements() { + + String statement = this.doPrepareStatement(); + return StringUtils.isEmpty(statement) ? Collections.emptyList() : Collections.singletonList(statement); } - private String queryString(DeclaredQuery query) { + private String doPrepareStatement() { + if (this.checkStatement(this.query.getStatementName())) { + return null; + } - String sql = query.getQueryString(); + switch (this.query.getSqlCommandType()) { + + case INSERT: + return this.insertStatement(); + case UPDATE: + return this.updateStatement(); + case DELETE: + return this.deleteStatement(); + case SELECT: + return this.selectStatement(); + default: + throw new MappingException("Unsupported SQL Command Type: " + this.query.getSqlCommandType().name()); + } + } + + private String selectStatement() { + MybatisQueryMethod method = this.query.getQueryMethod(); + + Map scopes = new HashMap<>(); + String sql = this.queryString(this.query.getQuery()); + + if (QueryUtils.hasConstructorExpression(sql)) { + String constructorExpression = QueryUtils.getConstructorExpression(sql); + String className = constructorExpression.substring(3, constructorExpression.lastIndexOf('(')).trim(); + Class clz; + try { + clz = ClassUtils.forName(className, this.getClass().getClassLoader()); + } + catch (ClassNotFoundException ex) { + throw new MappingException( + "Could not find class " + className + " from constructor expression: " + sql); + } + String columns = constructorExpression.substring(constructorExpression.lastIndexOf('(') + 1, + constructorExpression.length() - 1); + String[] columnList = columns.split(","); + sql = sql.replace(constructorExpression, Arrays.stream(columnList).map( + c -> String.format("%s AS %s", c.trim(), this.mappingContext.getDialect().quoteCertainly(c.trim()))) + .collect(Collectors.joining(","))); + sql = QueryUtils.quoteFieldAliases(sql, this.mappingContext.getDialect()); + + Constructor constructor = Arrays.stream(clz.getDeclaredConstructors()) + .filter(c -> c.getParameterCount() == columnList.length).findFirst().orElseThrow( + () -> new MappingException("Could not find constructor for: " + constructorExpression)); - sql = QueryUtils.quoteFieldAliases(sql, this.dialect); + List constructorParameters = new LinkedList<>(); + + for (int i = 0; i < constructor.getParameterCount(); i++) { + Parameter parameter = constructor.getParameters()[i]; + constructorParameters.add(new ConstructorParameter(columnList[i], parameter.getType().getName())); + } + scopes.put("constructorParameters", constructorParameters); + scopes.put("hasConstructor", true); + scopes.put("isResultMap", true); + scopes.put("result", ResidentStatementName.RESULT_MAP_PREFIX + this.query.getStatementName()); + scopes.put("resultMapType", className); + } + + MybatisParameters parameters = method.getParameters(); + if (parameters.hasSortParameter()) { + scopes.put("hasSort", true); + } + + if (method.isPageQuery()) { + scopes.put("isPageQuery", true); + scopes.put("countStatementName", this.query.getCountStatementName()); + scopes.put("countQuery", this.queryString(this.query.getCountQuery())); + } + + if (method.isPageQuery() || parameters.hasPageableParameter() || method.isSliceQuery()) { + scopes.put("pageable", true); + scopes.put("isUnpagedQuery", true); + scopes.put("unpagedStatementName", ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName()); + scopes.put("unpagedQuery", sql); + + RowSelection rowSelection = new RowSelection(true); + scopes.put("limitHandler", (Lambda) (frag, out) -> out.write( + this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), rowSelection))); + + } + + if (null != method.getResultMap() || SELECT_ALL_FROM.matcher(sql.toLowerCase()).matches()) { + scopes.putIfAbsent("isResultMap", true); + if (null != method.getResultMap()) { + scopes.putIfAbsent("result", method.getResultMap()); + } + else { + scopes.putIfAbsent("result", ResidentStatementName.RESULT_MAP); + } + } + else { + scopes.putIfAbsent("isResultMap", false); + scopes.putIfAbsent("result", method.getActualResultType()); + } + + scopes.put("query", sql); + return this.render("SimpleQuerySelect", scopes); + } + + private String deleteStatement() { + return this.render("SimpleQueryDelete", null); + } - List parameterBindings = query.getParameterBindings(); + private String updateStatement() { + return this.render("SimpleQueryUpdate", null); + } + + private String insertStatement() { + return this.render("SimpleQueryInsert", null); + } + + private String queryString(DeclaredQuery query) { + String sql = query.getQueryString(); + sql = QueryUtils.quoteFieldAliases(sql, this.mappingContext.getDialect()); + + List parameterBindings = query.getParameterBindings(); if (CollectionUtils.isEmpty(parameterBindings)) { return sql; } - for (StringQuery.ParameterBinding parameterBinding : parameterBindings) { - String replace = null; + + for (ParameterBinding parameterBinding : parameterBindings) { + String replace; String bindName = null; String typeHandler = ""; if (StringUtils.hasText(parameterBinding.getName())) { replace = ":" + parameterBinding.getRequiredName(); bindName = parameterBinding.getName(); - } else { replace = "?" + parameterBinding.getPosition(); @@ -103,12 +233,12 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { } } else { - MybatisParameters.MybatisParameter mp = this.query.getQueryMethod().getParameters() + MybatisParameter mp = this.query.getQueryMethod().getParameters() .getBindableParameter(parameterBinding.getRequiredPosition() - 1); bindName = mp.getName() .orElse(ResidentParameterName.POSITION_PREFIX + parameterBinding.getPosition()); - } + } } if (StringUtils.hasText(typeHandler)) { @@ -150,7 +280,7 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { break; } - sql = sql.replace(replace, String.format(" #{__bind_%s}", + sql = sql.replace(replace, String.format("#{__bind_%s}", bindName, like, bindName)); continue; @@ -158,92 +288,34 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler { } sql = sql.replace(replace, String.format("#{%s%s}", bindName, typeHandler)); + } return sql; - } @Override - protected String select() { - - MybatisQueryMethod method = this.query.getQueryMethod(); - String sql = this.mainQueryString(); - String unpaged = ""; - String sort = ""; - String count = ""; - String resultMap = null; - String result = ""; - - if (QueryUtils.hasConstructorExpression(sql)) { - String constructorExpression = QueryUtils.getConstructorExpression(sql); - - String className = constructorExpression.substring(3, constructorExpression.lastIndexOf("(")).trim(); - Class clz; - try { - clz = ClassUtils.forName(className, this.getClass().getClassLoader()); - - } - catch (ClassNotFoundException ex) { - throw new MappingException( - "Could not find class: " + className + " from constructor expression: " + sql); - } - String columns = constructorExpression.substring(constructorExpression.lastIndexOf("(") + 1, - constructorExpression.length() - 1); - String[] columnList = columns.split(","); - - sql = sql.replace(constructorExpression, - Stream.of(columnList) - .map(c -> String.format("%s as %s", c.trim(), dialect.quoteCertainly(c.trim()))) - .collect(Collectors.joining(","))); - sql = QueryUtils.quoteFieldAliases(sql, this.dialect); - StringBuilder results = new StringBuilder(); - results.append(""); - Constructor constructor = Stream.of(clz.getDeclaredConstructors()) - .filter(c -> c.getParameterCount() == columnList.length).findFirst().orElseThrow( - () -> new MappingException("Could not find constructor for: " + constructorExpression)); - - for (int i = 0; i < constructor.getParameterCount(); i++) { - Parameter parameter = constructor.getParameters()[i]; - results.append(String.format("", columnList[i].trim(), - parameter.getType().getName())); - } - - results.append(""); - resultMap = ResidentStatementName.RESULT_MAP_PREFIX + this.query.getStatementName(); - - result = String.format("%s", resultMap, className, - results.toString()); - - resultMap = String.format(" resultMap=\"%s\"", resultMap); - } - - MybatisParameters parameters = method.getParameters(); - if (parameters.hasSortParameter()) { - sort = this.buildStandardOrderBySegment(); - } - - if (method.isPageQuery()) { - count = String.format("", - this.query.getCountStatementName(), this.queryString(this.query.getCountQuery())); + protected String render(String name, Map scopes) { + if (null == scopes) { + scopes = new HashMap<>(); } + scopes.putIfAbsent(SCOPE_STATEMENT_NAME, this.query.getStatementName()); + scopes.putIfAbsent("query", this.queryString(this.query.getQuery())); + return super.render(name, scopes); + } - if (method.isPageQuery() || parameters.hasPageableParameter() || method.isSliceQuery()) { - unpaged = String.format("", - ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(), - (null != resultMap) ? resultMap : this.resultMapOrType(sql), sql + sort); - sql = this.dialect.getLimitHandler().processSql(sql + sort, new RowSelection(true)); - } + @Override + protected String getResource(String dir, String namespace) { + return "simple/" + this.query.getStatementId().replace('.', '/'); + } - String select = String.format("", this.query.getStatementName(), - (null != resultMap) ? resultMap : this.resultMapOrType(sql), sql); + @Data + @AllArgsConstructor + public static class ConstructorParameter { - return result + select + unpaged + count; + private String column; - } + private String javaType; - @Override - protected String getResourceSuffix() { - return "_simple_" + this.query.getQueryMethod().getStatementName() + super.getResourceSuffix(); } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java index 3419c143673fed786f5070006eb415bd6691be05..4352b6fb8e7ac5c15027195ac721c5abc7ef89ee 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java @@ -21,7 +21,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.data.auditing.config.AuditingHandlerBeanDefinitionParser; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.data.mybatis.domain.support.MybatisAuditingHandler; +import org.springframework.data.mybatis.auditing.MybatisAuditingHandler; import org.springframework.util.StringUtils; /** diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java index 25ac77bcf9975a79512605cd4fcec263fb3f4235..c7933dd58311cd0f01534761ab4e57f7c3e04c83 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java @@ -25,7 +25,8 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport; import org.springframework.data.auditing.config.AuditingConfiguration; -import org.springframework.data.mybatis.domain.support.MybatisAuditingHandler; +import org.springframework.data.mybatis.auditing.MybatisAuditingHandler; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -42,6 +43,20 @@ class MybatisAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { return EnableMybatisAuditing.class; } + @Override + protected String getAuditingHandlerBeanName() { + return "mybatisAuditingHandler"; + } + + @Override + public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { + + Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!"); + Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); + + super.registerBeanDefinitions(annotationMetadata, registry); + } + @Override protected MybatisAuditingConfiguration getConfiguration(AnnotationMetadata annotationMetadata) { return new MybatisAnnotationAuditingConfiguration(annotationMetadata, this.getAnnotation()); @@ -50,17 +65,13 @@ class MybatisAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { @Override protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition, BeanDefinitionRegistry registry) { + if (!registry.containsBeanDefinition(BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME)) { registry.registerBeanDefinition(BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME, // - new RootBeanDefinition(MybatisMappingContextFactoryBean.class)); + new RootBeanDefinition(MybatisMappingContext.class)); } } - @Override - protected String getAuditingHandlerBeanName() { - return "mybatisAuditingHandler"; - } - @Override protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) { Assert.notNull(configuration, "AuditingConfiguration must not be null!"); @@ -73,6 +84,7 @@ class MybatisAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { @Override protected BeanDefinitionBuilder configureDefaultAuditHandlerAttributes(AuditingConfiguration configuration, BeanDefinitionBuilder builder) { + BeanDefinitionBuilder beanDefinitionBuilder = super.configureDefaultAuditHandlerAttributes(configuration, builder); diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextFactoryBean.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextFactoryBean.java deleted file mode 100644 index 4d67d923c923279be09be140ddc98186766940ba..0000000000000000000000000000000000000000 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextFactoryBean.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2012-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.mybatis.repository.config; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import lombok.extern.slf4j.Slf4j; -import org.apache.ibatis.session.Configuration; -import org.mybatis.spring.SqlSessionTemplate; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy; -import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.lang.Nullable; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -/** - * {@link FactoryBean} to setup {@link MybatisMappingContext} instances from Spring - * configuration. - * - * @author JARVIS SONG - */ -@Slf4j -class MybatisMappingContextFactoryBean extends AbstractFactoryBean - implements ApplicationContextAware { - - private final Map, Class> mapping; - - private @Nullable ListableBeanFactory beanFactory; - - private Configuration configuration; - - MybatisMappingContextFactoryBean(Map, Class> mapping, SqlSessionTemplate sqlSessionTemplate) { - this.mapping = mapping; - this.configuration = sqlSessionTemplate.getConfiguration(); - } - - @Override - public Class getObjectType() { - return MybatisMappingContext.class; - } - - @Override - protected MybatisMappingContext createInstance() throws Exception { - if (log.isDebugEnabled()) { - log.debug("Initializing MybatisMappingContext..."); - } - Set> initialEntitySet; - if (null == this.mapping) { - initialEntitySet = new HashSet<>(); - } - else { - initialEntitySet = new HashSet<>(this.mapping.values()); - } - - MultiValueMap, Class> entityRepositoryMapping = new LinkedMultiValueMap<>(); - for (Map.Entry, Class> entry : this.mapping.entrySet()) { - Class repository = entry.getKey(); - Class entity = entry.getValue(); - entityRepositoryMapping.add(entity, repository); - } - - MybatisMappingContext context = new MybatisMappingContext(); - if (this.configuration.isMapUnderscoreToCamelCase()) { - context.setFieldNamingStrategy(new SnakeCaseFieldNamingStrategy()); - } - - context.setInitialEntitySet(initialEntitySet); - context.setEntityRepositoryMapping(entityRepositoryMapping); - context.initialize(); - if (log.isDebugEnabled()) { - log.debug("Finished initializing MybatisMappingContext!"); - } - - return context; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.beanFactory = applicationContext; - } - -} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextParser.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextParser.java new file mode 100644 index 0000000000000000000000000000000000000000..d1bb7c50df4665511779a40a29c0773ad5a5b725 --- /dev/null +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextParser.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-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.mybatis.repository.config; + +import java.util.Set; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.mybatis.mapping.MybatisEntityClassScanner; +import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.util.StringUtils; + +/** + * Spring Data Mybatis XML namespace parser for the {@code mybatis:mapping} element. + * + * @author JARVIS SONG + */ +class MybatisMappingContextParser extends AbstractSingleBeanDefinitionParser { + + @Override + protected Class getBeanClass(Element element) { + return MybatisMappingContext.class; + } + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + String id = super.resolveId(element, definition, parserContext); + + return StringUtils.hasText(id) ? id : BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + String packages = element.getAttribute("entity-base-packages"); + if (StringUtils.hasText(packages)) { + try { + Set> entityClasses = MybatisEntityClassScanner + .scan(StringUtils.commaDelimitedListToStringArray(packages)); + + builder.addPropertyValue("initialEntitySet", entityClasses); + } + catch (Exception ex) { + throw new IllegalArgumentException(String.format( + "encountered exception while scanning for entity classes in package(s) [%s]", packages), ex); + } + } + + String sqlSessionTemplateRef = element.getAttribute("sql-session-template-ref"); + if (StringUtils.hasText(sqlSessionTemplateRef)) { + builder.addConstructorArgReference(sqlSessionTemplateRef); + } + + String fieldNamingStrategyRef = element.getAttribute("field-naming-strategy-ref"); + if (StringUtils.hasText(fieldNamingStrategyRef)) { + builder.addPropertyReference("fieldNamingStrategy", fieldNamingStrategyRef); + } + + } + +} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java index bc3fcb1819899b7d8c863315a3a905dc5dbd3df3..8c0809a7f28fd07368b733442406b305c891f8fb 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java @@ -17,20 +17,9 @@ package org.springframework.data.mybatis.repository.config; import java.lang.annotation.Annotation; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.context.EnvironmentAware; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; -import org.springframework.data.repository.config.RepositoryConfigurationDelegate; +import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport; import org.springframework.data.repository.config.RepositoryConfigurationExtension; -import org.springframework.data.repository.config.RepositoryConfigurationUtils; -import org.springframework.util.Assert; /** * {@link ImportBeanDefinitionRegistrar} to enable {@link EnableMybatisRepositories} @@ -38,61 +27,16 @@ import org.springframework.util.Assert; * * @author JARVIS SONG */ -class MybatisRepositoriesRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { - - private Environment environment; - - private ResourceLoader resourceLoader; - - @Override - public void setEnvironment(Environment environment) { - - this.environment = environment; - } - - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - - this.resourceLoader = resourceLoader; - } +class MybatisRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport { @Override - public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry, - BeanNameGenerator generator) { - - Assert.notNull(metadata, "AnnotationMetadata must not be null!"); - Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); - Assert.notNull(this.resourceLoader, "ResourceLoader must not be null!"); - - // Guard against calls for sub-classes - if (metadata.getAnnotationAttributes(this.getAnnotation().getName()) == null) { - return; - } - - AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource( - metadata, this.getAnnotation(), this.resourceLoader, this.environment, registry, generator); - - RepositoryConfigurationExtension extension = this.getExtension(); - RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource); - - RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource, - this.resourceLoader, this.environment); - - delegate.registerRepositoriesIn(registry, extension); - } - - private RepositoryConfigurationExtension getExtension() { - return new MybatisRepositoryConfigExtension(this.resourceLoader); - } - - private Class getAnnotation() { + protected Class getAnnotation() { return EnableMybatisRepositories.class; } @Override - public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { - this.registerBeanDefinitions(annotationMetadata, registry, - ConfigurationClassPostProcessor.IMPORT_BEAN_NAME_GENERATOR); + protected RepositoryConfigurationExtension getExtension() { + return new MybatisRepositoryConfigExtension(); } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java index f40cc6416890ff03d94767998a44e4646bb10aa6..3dee9c98f3ec636f822a2f9c181318b9ea336418 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java @@ -20,9 +20,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Locale; -import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import javax.persistence.Embeddable; import javax.persistence.Entity; @@ -31,22 +29,14 @@ import javax.persistence.MappedSuperclass; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.io.ResourceLoader; -import org.springframework.data.mapping.MappingException; -import org.springframework.data.mybatis.dialect.DialectFactoryBean; import org.springframework.data.mybatis.repository.MybatisRepository; import org.springframework.data.mybatis.repository.support.MybatisRepositoryFactoryBean; import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; -import org.springframework.data.repository.config.RepositoryConfiguration; import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; import org.springframework.data.repository.config.RepositoryConfigurationSource; import org.springframework.data.repository.config.XmlRepositoryConfigurationSource; -import org.springframework.data.repository.core.support.AbstractRepositoryMetadata; import org.springframework.data.repository.util.TxUtils; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StopWatch; import org.springframework.util.StringUtils; /** @@ -61,18 +51,10 @@ public class MybatisRepositoryConfigExtension extends RepositoryConfigurationExt private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = TxUtils.DEFAULT_TRANSACTION_MANAGER; - private static final String DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME = "sqlSessionTemplate"; - private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions"; private static final String ESCAPE_CHARACTER_PROPERTY = "escapeCharacter"; - private final ResourceLoader resourceLoader; - - public MybatisRepositoryConfigExtension(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - @Override public String getModuleName() { return "MyBatis"; @@ -98,38 +80,14 @@ public class MybatisRepositoryConfigExtension extends RepositoryConfigurationExt return Arrays.asList(Entity.class, MappedSuperclass.class, Embeddable.class); } - @Override - public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource config) { - super.registerBeansForRoot(registry, config); - - Object source = config.getSource(); - Optional sqlSessionTemplateRef = config.getAttribute("sqlSessionTemplateRef"); - - registerIfNotAlreadyRegistered(() -> BeanDefinitionBuilder.rootBeanDefinition(DialectFactoryBean.class) - .addConstructorArgReference(sqlSessionTemplateRef.orElse(DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME)) - .getBeanDefinition(), registry, BeanDefinitionNames.DIALECT_BEAN_NAME, source); - - registerIfNotAlreadyRegistered( - () -> BeanDefinitionBuilder.rootBeanDefinition(MybatisMappingContextFactoryBean.class) - .addConstructorArgValue(this.scanDomains(config)) - .addConstructorArgReference( - sqlSessionTemplateRef.orElse(DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME)) - .getBeanDefinition(), - registry, BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME, source); - } - @Override public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource source) { Optional transactionManagerRef = source.getAttribute("transactionManagerRef"); builder.addPropertyValue("transactionManager", transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)); - Optional sqlSessionTemplateRef = source.getAttribute("sqlSessionTemplateRef"); - builder.addPropertyReference("sqlSessionTemplate", - sqlSessionTemplateRef.orElse(DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME)); builder.addPropertyValue(ESCAPE_CHARACTER_PROPERTY, getEscapeCharacter(source).orElse('\\')); builder.addPropertyReference("mappingContext", BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME); - builder.addPropertyReference("dialect", BeanDefinitionNames.DIALECT_BEAN_NAME); } @Override @@ -147,55 +105,11 @@ public class MybatisRepositoryConfigExtension extends RepositoryConfigurationExt } } - private Map, ? extends Class> scanDomains(RepositoryConfigurationSource source) { - StopWatch watch = new StopWatch(); - - if (log.isDebugEnabled()) { - log.debug("Scanning domains for repositories in packages {}.", - source.getBasePackages().stream().collect(Collectors.joining(", "))); - } - watch.start(); - - Collection> repositoryConfigurations = getRepositoryConfigurations( - source, this.resourceLoader, false); - - if (CollectionUtils.isEmpty(repositoryConfigurations)) { - return Collections.emptyMap(); - } - - Map, ? extends Class> mapping = repositoryConfigurations.stream() - .collect(Collectors.toMap(configuration -> { - try { - return Class.forName(configuration.getRepositoryInterface()); - } - catch (ClassNotFoundException ex) { - throw new MappingException(ex.getMessage(), ex); - } - }, configuration -> { - try { - Class repositoryClass = Class.forName(configuration.getRepositoryInterface()); - return AbstractRepositoryMetadata.getMetadata(repositoryClass).getDomainType(); - } - catch (ClassNotFoundException ex) { - throw new MappingException(ex.getMessage(), ex); - } - })); - - watch.stop(); - - if (log.isInfoEnabled()) { - log.info("Finished Domains scanning in {}ms. Found {} domains.", // - watch.getLastTaskTimeMillis(), mapping.size()); - } - - return mapping; - } - private static Optional getEscapeCharacter(RepositoryConfigurationSource source) { try { return source.getAttribute(ESCAPE_CHARACTER_PROPERTY, Character.class); } - catch (IllegalArgumentException ___) { + catch (IllegalArgumentException ex) { return Optional.empty(); } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java index 55649cdb41b66db1d022164f60ebf992c07b10b7..12b78c18bdabbbd84f46325b503d618c75c38644 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java @@ -16,6 +16,7 @@ package org.springframework.data.mybatis.repository.config; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; +import org.springframework.data.repository.config.RepositoryBeanDefinitionParser; /** * Simple namespace handler for {@literal repositories} namespace. @@ -27,9 +28,10 @@ public class MybatisRepositoryNameSpaceHandler extends NamespaceHandlerSupport { @Override public void init() { - RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(); - registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser); + registerBeanDefinitionParser("mapping", new MybatisMappingContextParser()); + registerBeanDefinitionParser("repositories", + new RepositoryBeanDefinitionParser(new MybatisRepositoryConfigExtension())); registerBeanDefinitionParser("auditing", new AuditingBeanDefinitionParser(BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME)); } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/RepositoryBeanDefinitionParser.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/RepositoryBeanDefinitionParser.java deleted file mode 100644 index 036e7407b2e58cf04de8fbed35db8bc765505b73..0000000000000000000000000000000000000000 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/RepositoryBeanDefinitionParser.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012-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.mybatis.repository.config; - -import org.w3c.dom.Element; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ReaderContext; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.beans.factory.xml.XmlReaderContext; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; -import org.springframework.data.config.ConfigurationUtils; -import org.springframework.data.repository.config.RepositoryConfigurationDelegate; -import org.springframework.data.repository.config.RepositoryConfigurationUtils; -import org.springframework.data.repository.config.XmlRepositoryConfigurationSource; -import org.springframework.lang.Nullable; - -/** - * Base class to implement repository namespaces. - * - * @author JARVIS SONG - * @since 2.0.0 - */ -public class RepositoryBeanDefinitionParser implements BeanDefinitionParser { - - @Override - @Nullable - public BeanDefinition parse(Element element, ParserContext parser) { - XmlReaderContext readerContext = parser.getReaderContext(); - - try { - - ResourceLoader resourceLoader = ConfigurationUtils.getRequiredResourceLoader(readerContext); - Environment environment = readerContext.getEnvironment(); - BeanDefinitionRegistry registry = parser.getRegistry(); - - XmlRepositoryConfigurationSource configSource = new XmlRepositoryConfigurationSource(element, parser, - environment); - RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, resourceLoader, - environment); - - MybatisRepositoryConfigExtension extension = new MybatisRepositoryConfigExtension(resourceLoader); - - RepositoryConfigurationUtils.exposeRegistration(extension, registry, configSource); - - for (BeanComponentDefinition definition : delegate.registerRepositoriesIn(registry, extension)) { - readerContext.fireComponentRegistered(definition); - } - - } - catch (RuntimeException ex) { - handleError(ex, element, readerContext); - } - - return null; - } - - private void handleError(Exception e, Element source, ReaderContext reader) { - reader.error(e.getMessage(), reader.extractSource(source), e); - } - -} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/AbstractMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/AbstractMybatisPrecompiler.java deleted file mode 100644 index a932f14acaa6b96c4db12654be6f5e464a77f3c3..0000000000000000000000000000000000000000 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/AbstractMybatisPrecompiler.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2012-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.mybatis.repository.query; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import javax.persistence.EmbeddedId; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; - -import com.samskivert.mustache.Mustache; -import lombok.extern.slf4j.Slf4j; -import org.apache.ibatis.builder.xml.XMLMapperBuilder; -import org.apache.ibatis.mapping.SqlCommandType; -import org.apache.ibatis.session.Configuration; - -import org.springframework.data.mapping.AssociationHandler; -import org.springframework.data.mapping.MappingException; -import org.springframework.data.mapping.PropertyHandler; -import org.springframework.data.mybatis.dialect.Dialect; -import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; -import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; -import org.springframework.data.mybatis.mapping.model.Column; -import org.springframework.data.mybatis.repository.support.ResidentParameterName; -import org.springframework.data.repository.core.RepositoryInformation; -import org.springframework.data.repository.query.parser.Part; -import org.springframework.util.StringUtils; - -/** - * Abstract mybatis precompiler. - * - * @author JARVIS SONG - */ -@Slf4j -abstract class AbstractMybatisPrecompiler implements MybatisPrecompiler { - - protected final MybatisMappingContext mappingContext; - - protected final Configuration configuration; - - protected final String namespace; - - protected final MybatisPersistentEntity persistentEntity; - - protected final Dialect dialect; - - protected Class repositoryInterface; - - protected EscapeCharacter escape; - - private final Mustache.Compiler mustache; - - AbstractMybatisPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect, - RepositoryInformation repositoryInformation) { - - this(mappingContext, configuration, dialect, repositoryInformation.getDomainType()); - - this.repositoryInterface = repositoryInformation.getRepositoryInterface(); - } - - AbstractMybatisPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect, - Class domainType) { - this.mappingContext = mappingContext; - this.configuration = configuration; - this.namespace = domainType.getName(); - this.persistentEntity = mappingContext.getRequiredPersistentEntity(domainType); - this.dialect = dialect; - - this.mustache = Mustache.compiler().withLoader(name -> { - String path = "org/springframework/data/mybatis/repository/query/template/" + name + ".mustache"; - InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path); - return new InputStreamReader(inputStream, StandardCharsets.UTF_8); - }).escapeHTML(false).withCollector(new DefaultCollector()); - } - - protected String render(String name, Object context) { - // Mustache.Compiler mustache = Mustache.compiler().escapeHTML(false); - String path = "org/springframework/data/mybatis/repository/query/template/" + name + ".mustache"; - try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path)) { - try (InputStreamReader source = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - return this.mustache.compile(source).execute(context); - } - catch (IOException ex) { - throw new MappingException("Could not render the statement: " + name, ex); - } - } - catch (IOException ex) { - throw new MappingException("Could not render the statement: " + name, ex); - } - } - - @Override - public void precompile() { - String xml = this.doPrecompile(); - - if (StringUtils.hasText(xml)) { - this.compileMapper(this.namespace, xml); - } - - } - - protected void compileMapper(String namespace, String content) { - String xml = "\n" - + "\n" - + "\n" + content + "\n"; - if (log.isDebugEnabled()) { - log.debug(xml); - } - try (InputStream inputStream = new ByteArrayInputStream(xml.getBytes())) { - XMLMapperBuilder mapperBuilder = new XMLMapperBuilder(inputStream, this.configuration, - this.namespace.replace('.', '/') + UUID.randomUUID().toString() + this.getResourceSuffix(), - this.configuration.getSqlFragments()); - mapperBuilder.parse(); - } - catch (IOException ex) { - throw new MappingException(ex.getMessage(), ex); - } - } - - protected abstract String doPrecompile(); - - protected String getResourceSuffix() { - return ".precompile"; - } - - protected String getTableName() { - return this.persistentEntity.getTable().getFullName(); - } - - protected Map mappingPropertyToColumn() { - Map map = new LinkedHashMap<>(); - - this.persistentEntity.doWithProperties((PropertyHandler) pp -> { - if (pp.isAnnotationPresent(EmbeddedId.class) || pp.isEmbeddable()) { - MybatisPersistentEntity embeddedEntity = this.mappingContext - .getRequiredPersistentEntity(pp.getActualType()); - embeddedEntity.doWithProperties((PropertyHandler) epp -> { - map.put(String.format("%s.%s", pp.getName(), epp.getName()), epp.getColumn()); - }); - return; - } - map.put(pp.getName(), pp.getColumn()); - }); - - this.persistentEntity.doWithAssociations((AssociationHandler) ass -> { - MybatisPersistentProperty inverse = ass.getInverse(); - - if (inverse.isAnnotationPresent(ManyToOne.class) || inverse.isAnnotationPresent(OneToOne.class)) { - - if (inverse.isAnnotationPresent(JoinTable.class)) { - return; - } - - MybatisPersistentEntity targetEntity = this.mappingContext - .getRequiredPersistentEntity(inverse.getActualType()); - - String columnName = null; - String referencedColumnName = null; - JoinColumn joinColumn = inverse.findAnnotation(JoinColumn.class); - if (null != joinColumn) { - if (StringUtils.hasText(joinColumn.name())) { - columnName = joinColumn.name(); - } - if (StringUtils.hasText(joinColumn.referencedColumnName())) { - referencedColumnName = joinColumn.referencedColumnName(); - } - - } - if (StringUtils.isEmpty(columnName)) { - columnName = inverse.getName() + "_" - + targetEntity.getRequiredIdProperty().getColumn().getName().render(this.dialect); - } - if (StringUtils.isEmpty(referencedColumnName)) { - referencedColumnName = targetEntity.getRequiredIdProperty().getColumn().getName() - .render(this.dialect); - } - map.put(String.format("%s.%s", inverse.getName(), targetEntity.getRequiredIdProperty().getName()), - new Column(columnName)); - - } - - }); - map.forEach((s, column) -> column.getName().setDialect(this.dialect)); - return map; - } - - protected List findProperties(MybatisPersistentEntity entity) { - List properties = new ArrayList<>(); - entity.doWithProperties((PropertyHandler) properties::add); - return properties; - } - - protected List findProperties() { - return this.findProperties(this.persistentEntity); - } - - protected SqlCommandType extractSqlCommandType(String queryString) { - if (StringUtils.isEmpty(queryString)) { - return SqlCommandType.UNKNOWN; - } - - queryString = queryString.trim().toLowerCase(); - if (queryString.startsWith("insert")) { - return SqlCommandType.INSERT; - } - if (queryString.startsWith("update")) { - return SqlCommandType.UPDATE; - } - if (queryString.startsWith("delete")) { - return SqlCommandType.DELETE; - } - if (queryString.startsWith("select")) { - return SqlCommandType.SELECT; - } - - return SqlCommandType.UNKNOWN; - } - - protected boolean canUpperCase(MybatisPersistentProperty property) { - return String.class.equals(property.getType()); - } - - protected String buildQueryByConditionOperator(Part.Type type) { - switch (type) { - case BETWEEN: - return " BETWEEN "; - case SIMPLE_PROPERTY: - return "="; - case NEGATING_SIMPLE_PROPERTY: - return "]]>"; - case LESS_THAN: - case BEFORE: - return ""; - case LESS_THAN_EQUAL: - return ""; - case GREATER_THAN: - case AFTER: - return "]]>"; - case GREATER_THAN_EQUAL: - return ">="; - case NOT_LIKE: - case NOT_CONTAINING: - return " NOT LIKE "; - case LIKE: - case STARTING_WITH: - case ENDING_WITH: - case CONTAINING: - return " LIKE "; - case IN: - return " IN "; - case NOT_IN: - return " NOT IN "; - } - - return ""; - } - - protected String buildQueryByConditionLeftSegment(String column, Part.IgnoreCaseType ignoreCaseType, - MybatisPersistentProperty property) { - switch (ignoreCaseType) { - - case ALWAYS: - return this.dialect.getLowercaseFunction() + "(" + column + ")"; - case WHEN_POSSIBLE: - if ((null != property) && this.canUpperCase(property)) { - return this.dialect.getLowercaseFunction() + "(" + column + ")"; - } - return column; - case NEVER: - default: - return column; - } - } - - protected String buildQueryByConditionRightSegment(Part.Type type, Part.IgnoreCaseType ignoreCaseType, - String[] properties, Column column) { - switch (type) { - case BETWEEN: - return String.format("#{%s} and #{%s}", properties[0], properties[1]); - case IS_NOT_NULL: - return " IS NOT NULL"; - case IS_NULL: - return " IS NULL"; - case STARTING_WITH: - return this.buildLikeRightSegment(properties[0], false, true, ignoreCaseType); - case ENDING_WITH: - return this.buildLikeRightSegment(properties[0], true, false, ignoreCaseType); - case NOT_CONTAINING: - case CONTAINING: - case LIKE: - return this.buildLikeRightSegment(properties[0], true, true, ignoreCaseType); - case NOT_IN: - case IN: - return String.format( - "#{__item}", - properties[0]); - case TRUE: - return " = 1"; - case FALSE: - return " = 0"; - default: - if (ignoreCaseType == Part.IgnoreCaseType.ALWAYS || ignoreCaseType == Part.IgnoreCaseType.WHEN_POSSIBLE) { - if (null != column.getTypeHandler()) { - return String.format("%s(#{%s,javaType=%s,typeHandler=%s})", this.dialect.getLowercaseFunction(), - properties[0], column.getJavaType().getName(), column.getTypeHandler().getName()); - } - return String.format("%s(#{%s})", this.dialect.getLowercaseFunction(), properties[0]); - } - if (null != column.getTypeHandler()) { - return String.format("#{%s,javaType=%s,typeHandler=%s}", properties[0], column.getJavaType().getName(), - column.getTypeHandler().getName()); - } - return String.format("#{%s}", properties[0]); - - } - } - - protected String buildLikeRightSegment(String property, boolean left, boolean right, - Part.IgnoreCaseType ignoreCaseType) { - return String.format("%s", property, (left ? "'%' + " : ""), - property, (right ? " + '%'" : ""), - (((ignoreCaseType == Part.IgnoreCaseType.ALWAYS) - || (ignoreCaseType == Part.IgnoreCaseType.WHEN_POSSIBLE)) - ? String.format("%s(#{__bind_%s})", this.dialect.getLowercaseFunction(), property) - : String.format("#{__bind_%s}", property))); - } - - protected String buildStandardOrderBySegment() { - String mapping = this.mappingPropertyToColumn().entrySet().stream() - .map(entry -> String.format("'%s':'%s'", entry.getKey(), - entry.getValue().getName().render(this.dialect))) - .collect(Collectors.joining(",")); - String bind = String.format("", mapping); - String sql = String.format("order by " - + " " - + "%s(" + "${__columnsMap[item.property]}" - + ") " + "${item.direction.name().toLowerCase()}" + "", - ResidentParameterName.SORT, this.dialect.getLowercaseFunction()); - return String.format("%s %s", ResidentParameterName.SORT, bind, sql); - } - -} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java index a106f4fcc2a55b2946003e5bb0b24da9d1e22239..4896ecbfeba16d604bbfb25050996dafb25ecb55 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java @@ -54,7 +54,7 @@ public class MybatisParameters extends Parameters getReturnType() { + public Class getReturnType() { return this.method.getReturnType(); } - String getActualResultType() { + public String getActualResultType() { Class type = this.getReturnType(); if (type == Map.class) { return "map"; diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryMethodPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryMethodPrecompiler.java deleted file mode 100644 index 38e2236e4714d3a8e2fe0c99c36c3bc5961a4660..0000000000000000000000000000000000000000 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryMethodPrecompiler.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2012-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.mybatis.repository.query; - -import java.util.regex.Pattern; - -import org.apache.ibatis.session.Configuration; - -import org.springframework.data.mapping.MappingException; -import org.springframework.data.mybatis.dialect.Dialect; -import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.data.mybatis.repository.support.ResidentStatementName; - -/** - * . - * - * @author JARVIS SONG - */ -abstract class MybatisQueryMethodPrecompiler extends AbstractMybatisPrecompiler { - - private static final Pattern SELECT_ALL_FROM = Pattern.compile("^\\s*select\\s+\\*\\s+from\\s+.*", - Pattern.CASE_INSENSITIVE); - - protected final AbstractMybatisQuery query; - - MybatisQueryMethodPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect, - AbstractMybatisQuery query) { - super(mappingContext, configuration, dialect, query.getQueryMethod().getEntityInformation().getJavaType()); - - this.query = query; - } - - @Override - protected String doPrecompile() { - - if (this.configuration.hasStatement(this.query.getStatementId(), false)) { - return ""; - } - - switch (this.query.getSqlCommandType()) { - - case INSERT: - return this.insert(); - case UPDATE: - return this.update(); - case DELETE: - return this.delete(); - case SELECT: - return this.select(); - default: - throw new MappingException("Unsupported SQL Command Type: " + this.query.getSqlCommandType().name()); - - } - - } - - protected String insert() { - return String.format("%s", this.query.getStatementName(), this.mainQueryString()); - } - - protected String update() { - return String.format("%s", this.query.getStatementName(), this.mainQueryString()); - } - - protected String delete() { - return String.format("%s", this.query.getStatementName(), this.mainQueryString()); - } - - protected String select() { - String sql = this.mainQueryString(); - return String.format("", this.query.getStatementName(), - this.resultMapOrType(sql), sql); - } - - protected String resultMapOrType(String sql) { - MybatisQueryMethod method = this.query.getQueryMethod(); - - return String.format("%s=\"%s\"", - (null != method.getResultMap() || SELECT_ALL_FROM.matcher(sql.toLowerCase()).matches()) ? "resultMap" - : "resultType", - ((null != method.getResultMap()) ? method.getResultMap() : // - (SELECT_ALL_FROM.matcher(sql).matches() ? // - ResidentStatementName.RESULT_MAP : // - method.getActualResultType()))); - } - - protected abstract String mainQueryString(); - -} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisPrecompiler.java deleted file mode 100644 index e77309a9e291060bc97cc89c5b91b9ac27334698..0000000000000000000000000000000000000000 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisPrecompiler.java +++ /dev/null @@ -1,906 +0,0 @@ -/* - * Copyright 2012-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.mybatis.repository.query; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.persistence.EmbeddedId; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.SequenceGenerator; -import javax.persistence.SequenceGenerators; - -import com.samskivert.mustache.Mustache; -import com.samskivert.mustache.Mustache.InvertibleLambda; -import com.samskivert.mustache.Template.Fragment; -import org.apache.ibatis.session.Configuration; - -import org.springframework.data.mapping.AssociationHandler; -import org.springframework.data.mapping.MappingException; -import org.springframework.data.mapping.PropertyHandler; -import org.springframework.data.mybatis.annotation.Condition; -import org.springframework.data.mybatis.annotation.Conditions; -import org.springframework.data.mybatis.annotation.Example; -import org.springframework.data.mybatis.dialect.Dialect; -import org.springframework.data.mybatis.dialect.pagination.RowSelection; -import org.springframework.data.mybatis.dialect.pagination.SQLServer2005LimitHandler; -import org.springframework.data.mybatis.dialect.pagination.SQLServer2012LimitHandler; -import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; -import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; -import org.springframework.data.mybatis.mapping.model.Association; -import org.springframework.data.mybatis.mapping.model.Collection; -import org.springframework.data.mybatis.mapping.model.Column; -import org.springframework.data.mybatis.mapping.model.ColumnResult; -import org.springframework.data.mybatis.repository.MybatisExampleRepository; -import org.springframework.data.mybatis.repository.support.ResidentStatementName; -import org.springframework.data.mybatis.repository.support.SqlSessionRepositorySupport; -import org.springframework.data.repository.core.RepositoryInformation; -import org.springframework.data.repository.query.parser.Part; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; - -/** - * Simple mybatis precompiler. - * - * @author JARVIS SONG - */ -class SimpleMybatisPrecompiler extends AbstractMybatisPrecompiler { - - static final String DEFAULT_SEQUENCE_NAME = "seq_spring_data_mybatis"; - - SimpleMybatisPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect, - RepositoryInformation repositoryInformation) { - super(mappingContext, configuration, dialect, repositoryInformation); - } - - @Override - protected String doPrecompile() { - StringBuilder builder = new StringBuilder(); - - // SQL Fragments - // __base_column_list - builder.append(this.addBaseColumnListSQL()); - // __query_by_example_where_clause - builder.append(this.addQueryByExampleWhereClauseSQL()); - // __standard_sort - builder.append(this.addStandardSortSQL()); - // __where_clause_by_fixed_id - builder.append(this.addWhereClauseByFixedIdSQL()); - // __where_clause_by_entity - builder.append(this.addWhereClauseByEntitySQL()); - // __where_clause_by_id - builder.append(this.addWhereClauseByIdSQL()); - // __where_clause_by_ids - builder.append(this.addWhereClauseByIdsSQL()); - // ResultMap - builder.append(this.addResultMap()); - - // Statements - builder.append(this.addInsertStatement(true)); - builder.append(this.addInsertStatement(false)); - builder.append(this.addUpdateStatement(true, true)); - builder.append(this.addUpdateStatement(true, false)); - builder.append(this.addUpdateStatement(false, true)); - builder.append(this.addUpdateStatement(false, false)); - builder.append(this.addDeleteByIdStatement()); - builder.append(this.addDeleteByIdsStatement()); - builder.append(this.addDeleteAllStatement()); - builder.append(this.addGetByIdStatement()); - builder.append(this.addFindStatement(true)); - builder.append(this.addFindStatement(false)); - builder.append(this.addCountAllStatement()); - builder.append(this.addCountStatement()); - - builder.append(this.addQueryByExample()); - builder.append(this.addQueryByExampleForPage()); - builder.append(this.addCountQueryByExample()); - - if (null != this.repositoryInterface - && MybatisExampleRepository.class.isAssignableFrom(this.repositoryInterface)) { - if (this.persistentEntity.isAnnotationPresent(Example.class)) { - - try { - ClassUtils.forName(this.persistentEntity.getType().getName() + "Example", - this.persistentEntity.getType().getClassLoader()); - } - catch (ClassNotFoundException ex) { - throw new MappingException( - "Are you forget to generate " + this.persistentEntity.getType().getName() + "Example ?"); - } - - builder.append(this.addFindByExampleWhereClauseSQL()); - builder.append(this.addFindByExampleStatement()); - } - else { - throw new MappingException(String.format( - "The %s extends MybatisExampleRepository, but could not find @Example on the entity: %s", - this.repositoryInterface.getName(), this.persistentEntity.getType().getName())); - } - } - return builder.toString(); - } - - protected boolean checkSqlFragment(String statementName) { - return this.configuration.getSqlFragments() - .containsKey(this.namespace + SqlSessionRepositorySupport.DOT + statementName); - } - - protected boolean checkStatement(String statementName) { - return this.configuration.hasStatement(this.namespace + SqlSessionRepositorySupport.DOT + statementName, false); - } - - private String addBaseColumnListSQL() { - if (this.checkSqlFragment(ResidentStatementName.BASE_COLUMN_LIST)) { - return ""; - } - Map params = new HashMap<>(); - params.put("statementName", ResidentStatementName.BASE_COLUMN_LIST); - params.put("columns", this.mappingPropertyToColumn().values().stream() - .map(c -> c.getName().render(this.dialect)).collect(Collectors.joining(","))); - return this.render("BasicColumns", params); - } - - private String addQueryByExampleWhereClauseSQL() { - if (this.checkSqlFragment(ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE); - scopes.put("properties", this.mappingPropertyToColumn().entrySet()); - scopes.put("testNotNull", this.lambdaTestNotNull()); - scopes.put("dialect", this.dialect); - scopes.put("replaceDotToUnderline", this.lambdaReplaceDotToUnderline()); - scopes.put("regexLike", this.lambdaRegexLike()); - return this.render("QueryByExampleWhereClause", scopes); - } - - private String addStandardSortSQL() { - if (this.checkSqlFragment(ResidentStatementName.STANDARD_SORT)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.STANDARD_SORT); - scopes.put("columnsMap", - this.mappingPropertyToColumn().entrySet().stream() - .map(entry -> String.format("'%s':'%s'", entry.getKey(), - entry.getValue().getName().render(this.dialect))) - .collect(Collectors.joining(","))); - scopes.put("lowercaseFunction", this.dialect.getLowercaseFunction()); - return this.render("StandardSort", scopes); - } - - private String addWhereClauseByFixedIdSQL() { - if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_FIXED_ID_CLAUSE)) { - return ""; - } - MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty(); - - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.WHERE_BY_FIXED_ID_CLAUSE); - scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class)); - if ((Boolean) scopes.get("embedded")) { - scopes.put("properties", - this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType()))); - } - else { - scopes.put("properties", this.findProperties()); - } - return this.render("WhereClauseByFixedId", scopes); - } - - private String addWhereClauseByEntitySQL() { - if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_ENTITY_CLAUSE)) { - return ""; - } - MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty(); - - Map scopes = new HashMap<>(); - scopes.put("idPropertyName", idProperty.getName()); - scopes.put("statementName", ResidentStatementName.WHERE_BY_ENTITY_CLAUSE); - scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class)); - if ((Boolean) scopes.get("embedded")) { - scopes.put("properties", - this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType()))); - } - else { - scopes.put("properties", this.findProperties()); - } - return this.render("WhereClauseByEntity", scopes); - - } - - private String addWhereClauseByIdSQL() { - if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_ID_CLAUSE)) { - return ""; - } - MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty(); - Map scopes = new HashMap<>(); - scopes.put("idPropertyName", idProperty.getName()); - scopes.put("statementName", ResidentStatementName.WHERE_BY_ID_CLAUSE); - scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class)); - if ((Boolean) scopes.get("embedded")) { - scopes.put("properties", - this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType()))); - } - else { - scopes.put("properties", this.findProperties()); - } - return this.render("WhereClauseById", scopes); - } - - private String addWhereClauseByIdsSQL() { - if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_IDS_CLAUSE) - || null == this.persistentEntity.getIdClass()) { - return ""; - } - MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty(); - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.WHERE_BY_IDS_CLAUSE); - scopes.put("idProperty", idProperty); - scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class)); - if ((Boolean) scopes.get("embedded")) { - scopes.put("properties", - this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType()))); - } - return this.render("WhereClauseByIds", scopes); - - } - - private String addResultMap() { - Map params = new HashMap<>(); - List results = new LinkedList<>(); - List embeddedAssociations = new ArrayList<>(); - - this.persistentEntity.doWithProperties((PropertyHandler) pp -> { - if (pp.isAnnotationPresent(EmbeddedId.class) || pp.isEmbeddable()) { - MybatisPersistentEntity embeddedEntity = this.mappingContext - .getRequiredPersistentEntity(pp.getActualType()); - embeddedEntity.doWithProperties((PropertyHandler) epp -> { - ColumnResult cr = this.columnResult(epp); - cr.setPrimaryKey(pp.isAnnotationPresent(EmbeddedId.class)); - cr.setProperty(pp.getName() + "." + epp.getName()); - results.add(cr); - }); - - return; - } - results.add(this.columnResult(pp)); - }); - results.sort((o1, o2) -> o1.isPrimaryKey() ? -1 : 1); - List associations = new ArrayList<>(); - List collections = new ArrayList<>(); - this.persistentEntity.doWithAssociations((AssociationHandler) ass -> { - MybatisPersistentProperty inverse = ass.getInverse(); - if (inverse.isAnnotationPresent(ManyToOne.class) || inverse.isAnnotationPresent(OneToOne.class)) { - MybatisPersistentEntity targetEntity = this.mappingContext - .getRequiredPersistentEntity(inverse.getActualType()); - String namespace = targetEntity.getType().getName(); - - Association association = new Association().setProperty(inverse.getName()) - .setJavaType(inverse.getActualType().getName()) - .setTargetTable(targetEntity.getTable().getFullName()); - String fetch = null; - ManyToOne manyToOne = inverse.findAnnotation(ManyToOne.class); - if (null != manyToOne) { - fetch = manyToOne.fetch().name().toLowerCase(); - } - else { - OneToOne oneToOne = inverse.findAnnotation(OneToOne.class); - if (null != oneToOne) { - fetch = oneToOne.fetch().name().toLowerCase(); - } - } - association.setFetch(fetch); - - List joinColumns = new ArrayList<>(); - - JoinColumns joinColumnsAnn = inverse.findAnnotation(JoinColumns.class); - if (null != joinColumnsAnn && null != joinColumnsAnn.value() && joinColumnsAnn.value().length > 0) { - for (JoinColumn joinColumn : joinColumnsAnn.value()) { - joinColumns.add(new Association.JoinColumn( - StringUtils.hasText(joinColumn.name()) ? joinColumn.name() - : targetEntity.getTable().getName() + "_" - + targetEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - StringUtils.hasText(joinColumn.referencedColumnName()) - ? joinColumn.referencedColumnName() : this.persistentEntity.getIdProperty() - .getColumn().getName().render(this.dialect))); - } - } - JoinColumn joinColumnAnn = inverse.findAnnotation(JoinColumn.class); - if (null != joinColumnAnn) { - joinColumns - .add(new Association.JoinColumn( - StringUtils.hasText(joinColumnAnn.name()) ? joinColumnAnn.name() - : targetEntity.getTable().getName() + "_" - + targetEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - StringUtils.hasText(joinColumnAnn.referencedColumnName()) - ? joinColumnAnn.referencedColumnName() : this.persistentEntity - .getIdProperty().getColumn().getName().render(this.dialect))); - } - - if (joinColumns.isEmpty()) { - joinColumns.add(new Association.JoinColumn( - targetEntity.getTable().getName() + "_" - + targetEntity.getIdProperty().getColumn().getName().render(this.dialect), - this.persistentEntity.getIdProperty().getColumn().getName().render(this.dialect))); - } - - association.setJoinColumns(joinColumns) - .setSelect(namespace + '.' + this.addAssociationManyToOne(namespace, association)); - - associations.add(association); - } - - if (inverse.isAnnotationPresent(ManyToMany.class) || inverse.isAnnotationPresent(OneToMany.class)) { - MybatisPersistentEntity targetEntity = this.mappingContext - .getRequiredPersistentEntity(inverse.getActualType()); - - String namespace = targetEntity.getType().getName(); - Collection collection = new Collection().setProperty(inverse.getName()) - .setOfType(inverse.getActualType().getName()) - .setTargetTable(targetEntity.getTable().getFullName()); - - OrderBy orderBy = inverse.findAnnotation(OrderBy.class); - if (null != orderBy) { - if (StringUtils.hasText(orderBy.value())) { - collection.setOrder(orderBy.value()); - } - else if (targetEntity.hasIdProperty() && !targetEntity.hasCompositeId()) { - collection.setOrder( - targetEntity.getIdProperty().getColumn().getName().render(this.dialect) + " ASC"); - } - } - - ManyToMany manyToMany = inverse.findAnnotation(ManyToMany.class); - if (null != manyToMany) { - collection.setManyToMany(true).setFetch(manyToMany.fetch().name().toLowerCase()); - JoinTable joinTable = inverse.findAnnotation(JoinTable.class); - if (null != joinTable) { - Collection.JoinTable jt = new Collection.JoinTable(StringUtils.hasText(joinTable.name()) - ? joinTable.name() : (this.persistentEntity.getTable().getName() + "_" - + targetEntity.getTable().getName())); - - JoinColumn[] joinColumns = joinTable.joinColumns(); - if (null == joinColumns || joinColumns.length == 0) { - jt.addJoinColumn(new Collection.JoinColumn( - this.persistentEntity.getTable().getName() + "_" - + this.persistentEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - this.persistentEntity.getIdProperty().getColumn().getName().render(this.dialect))); - } - else { - for (JoinColumn joinColumn : joinColumns) { - jt.addJoinColumn(new Collection.JoinColumn(joinColumn.name(), - joinColumn.referencedColumnName())); - } - } - - JoinColumn[] inverseJoinColumns = joinTable.inverseJoinColumns(); - if (null == inverseJoinColumns || inverseJoinColumns.length == 0) { - jt.addInverseJoinColumns( - new Collection.JoinColumn( - targetEntity.getTable().getName() + "_" - + targetEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - targetEntity.getIdProperty().getColumn().getName().render(this.dialect))); - } - else { - for (JoinColumn joinColumn : inverseJoinColumns) { - jt.addInverseJoinColumns(new Collection.JoinColumn(joinColumn.name(), - joinColumn.referencedColumnName())); - } - } - collection.setJoinTable(jt); - } - else { - collection.setJoinTable(new Collection.JoinTable( - this.persistentEntity.getTable().getName() + "_" + targetEntity.getTable().getName()) - .addJoinColumn(new Collection.JoinColumn( - this.persistentEntity.getTable().getName() + "_" - + this.persistentEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - this.persistentEntity.getIdProperty().getColumn().getName() - .render(this.dialect))) - .addInverseJoinColumns(new Collection.JoinColumn( - targetEntity.getTable().getName() + "_" - + targetEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - targetEntity.getIdProperty().getColumn().getName() - .render(this.dialect)))); - } - collection.setSelect(namespace + '.' + this.addAssociationManyToMany(namespace, collection)); - } - else { - OneToMany oneToMany = inverse.findAnnotation(OneToMany.class); - if (null != oneToMany) { - collection.setManyToMany(false).setFetch(oneToMany.fetch().name().toLowerCase()); - - List joinColumns = new ArrayList<>(); - - JoinColumns joinColumnsAnn = inverse.findAnnotation(JoinColumns.class); - if (null != joinColumnsAnn && null != joinColumnsAnn.value() - && joinColumnsAnn.value().length > 0) { - for (JoinColumn joinColumn : joinColumnsAnn.value()) { - joinColumns.add(new Collection.JoinColumn( - StringUtils.hasText(joinColumn.name()) ? joinColumn.name() - : this.persistentEntity.getTable().getName() + "_" - + this.persistentEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - StringUtils.hasText(joinColumn.referencedColumnName()) - ? joinColumn.referencedColumnName() : this.persistentEntity - .getIdProperty().getColumn().getName().render(this.dialect))); - } - } - JoinColumn joinColumnAnn = inverse.findAnnotation(JoinColumn.class); - if (null != joinColumnAnn) { - joinColumns.add(new Collection.JoinColumn( - StringUtils.hasText(joinColumnAnn.name()) ? joinColumnAnn.name() - : this.persistentEntity.getTable().getName() + "_" - + this.persistentEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - StringUtils.hasText(joinColumnAnn.referencedColumnName()) - ? joinColumnAnn.referencedColumnName() : this.persistentEntity - .getIdProperty().getColumn().getName().render(this.dialect))); - } - - if (joinColumns.isEmpty()) { - joinColumns.add(new Collection.JoinColumn( - this.persistentEntity.getTable().getName() + "_" - + this.persistentEntity.getIdProperty().getColumn().getName() - .render(this.dialect), - this.persistentEntity.getIdProperty().getColumn().getName().render(this.dialect))); - } - - collection.setJoinColumns(joinColumns) - .setSelect(namespace + '.' + this.addAssociationOneToMany(namespace, collection)); - } - } - collections.add(collection); - } - }); - - params.put("statementName", ResidentStatementName.RESULT_MAP); - params.put("entityType", this.persistentEntity.getType().getName()); - params.put("results", results); - params.put("embeddedAssociations", embeddedAssociations); - params.put("associations", associations); - params.put("collections", collections); - - // avoid custom __result_map in mapper file, but has not generate association - // select statement. - if (this.configuration.hasResultMap(this.namespace + '.' + ResidentStatementName.RESULT_MAP)) { - return ""; - } - - return this.render("ResultMap", params); - } - - private String addAssociationManyToOne(String namespace, Association association) { - String statementName = "__association_to_one_" + this.persistentEntity.getName().replace('.', '_') + "_" - + association.getProperty(); - Map scopes = new HashMap<>(); - scopes.put("statementName", statementName); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - scopes.put("association", association); - this.compileMapper(namespace, this.render("AssociationManyToOne", scopes)); - - return statementName; - } - - private String addAssociationManyToMany(String namespace, Collection collection) { - String statementName = "__association_many_to_many_" + this.persistentEntity.getName().replace('.', '_') + "_" - + collection.getProperty(); - Map scopes = new HashMap<>(); - scopes.put("statementName", statementName); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - scopes.put("collection", collection); - this.compileMapper(namespace, this.render("AssociationManyToMany", scopes)); - - return statementName; - } - - private String addAssociationOneToMany(String namespace, Collection collection) { - String statementName = "__association_one_to_many_" + this.persistentEntity.getName().replace('.', '_') + "_" - + collection.getProperty(); - Map scopes = new HashMap<>(); - scopes.put("statementName", statementName); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - scopes.put("collection", collection); - this.compileMapper(namespace, this.render("AssociationOneToMany", scopes)); - - return statementName; - } - - private String addInsertStatement(boolean selective) { - if (this.checkStatement(selective ? ResidentStatementName.INSERT_SELECTIVE : ResidentStatementName.INSERT)) { - return ""; - } - - MybatisPersistentProperty idProperty = this.persistentEntity.getIdProperty(); - String keyProperty = ""; - String keyColumn = ""; - boolean useGeneratedKeys = false; - boolean excludeId = false; - - if (!this.persistentEntity.hasCompositeId() && null != idProperty) { - keyProperty = idProperty.getName(); - keyColumn = idProperty.getColumn().getName().getText(); - if (idProperty.isAnnotationPresent(GeneratedValue.class)) { - useGeneratedKeys = true; - excludeId = true; - } - } - - Map scopes = new HashMap<>(); - scopes.put("statementName", selective ? ResidentStatementName.INSERT_SELECTIVE : ResidentStatementName.INSERT); - scopes.put("properties", this.mappingPropertyToColumn().entrySet()); - scopes.put("table", this.getTableName()); - scopes.put("parameterType", this.persistentEntity.getType().getName()); - scopes.put("selective", selective); - scopes.put("keyProperty", keyProperty); - scopes.put("keyColumn", keyColumn); - scopes.put("useGeneratedKeys", useGeneratedKeys); - scopes.put("testNotNull", this.lambdaTestNotNull()); - - if (useGeneratedKeys) { - scopes.putAll(this.buildKeyGenerator(idProperty)); - } - - scopes.put("excludeId", !"BEFORE".equals(scopes.get("order")) && excludeId); - - return this.render("Insert", scopes); - - } - - private Map buildKeyGenerator(MybatisPersistentProperty idProperty) { - Map result = new HashMap<>(); - boolean executeBefore; - String sql; - GeneratedValue gv = idProperty.getRequiredAnnotation(GeneratedValue.class); - if (gv.strategy() == GenerationType.IDENTITY || (gv.strategy() == GenerationType.AUTO - && "identity".equals(this.dialect.getNativeIdentifierGeneratorStrategy()))) { - // identity - sql = this.dialect.getIdentityColumnSupport().getIdentitySelectString(this.getTableName(), - idProperty.getColumn().getName().getCanonicalName(), - idProperty.getColumn().getJdbcType().TYPE_CODE); - executeBefore = false; - } - else if (gv.strategy() == GenerationType.SEQUENCE || (gv.strategy() == GenerationType.AUTO - && "sequence".equals(this.dialect.getNativeIdentifierGeneratorStrategy()))) { - String sequenceName = DEFAULT_SEQUENCE_NAME; - if (StringUtils.hasText(gv.generator())) { - // search sequence generator - Map sequenceGenerators = new HashMap<>(); - if (this.persistentEntity.isAnnotationPresent(SequenceGenerators.class)) { - sequenceGenerators.putAll(Stream - .of(this.persistentEntity.getRequiredAnnotation(SequenceGenerators.class).value()) - .filter(sg -> StringUtils.hasText(sg.sequenceName())) - .collect(Collectors.toMap(SequenceGenerator::name, SequenceGenerator::sequenceName))); - } - if (this.persistentEntity.isAnnotationPresent(SequenceGenerator.class)) { - SequenceGenerator sg = this.persistentEntity.getRequiredAnnotation(SequenceGenerator.class); - if (StringUtils.hasText(sg.sequenceName())) { - sequenceGenerators.put(sg.name(), sg.sequenceName()); - } - } - if (idProperty.isAnnotationPresent(SequenceGenerators.class)) { - sequenceGenerators.putAll(Stream - .of(idProperty.getRequiredAnnotation(SequenceGenerators.class).value()) - .filter((sg) -> StringUtils.hasText(sg.sequenceName())) - .collect(Collectors.toMap(SequenceGenerator::name, SequenceGenerator::sequenceName))); - } - if (idProperty.isAnnotationPresent(SequenceGenerator.class)) { - SequenceGenerator sg = idProperty.getRequiredAnnotation(SequenceGenerator.class); - if (StringUtils.hasText(sg.sequenceName())) { - sequenceGenerators.put(sg.name(), sg.sequenceName()); - } - } - String sn = sequenceGenerators.get(gv.generator()); - if (StringUtils.hasText(sn)) { - sequenceName = sn; - } - } - sql = this.dialect.getSequenceNextValString(sequenceName); - executeBefore = true; - } - else { - throw new UnsupportedOperationException("unsupported generated value id strategy: " + gv.strategy()); - } - result.put("order", executeBefore ? "BEFORE" : "AFTER"); - result.put("keySql", sql); - result.put("keyType", idProperty.getType().getName()); - return result; - } - - private String addUpdateStatement(boolean selective, boolean byId) { - String statement = (selective - ? (byId ? ResidentStatementName.UPDATE_SELECTIVE_BY_ID : ResidentStatementName.UPDATE_SELECTIVE) - : (byId ? ResidentStatementName.UPDATE_BY_ID : ResidentStatementName.UPDATE)); - if (this.checkStatement(statement) || null == this.persistentEntity.getIdClass()) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", statement); - scopes.put("selective", selective); - scopes.put("properties", this.mappingPropertyToColumn().entrySet()); - scopes.put("table", this.getTableName()); - scopes.put("testNotNull", this.lambdaTestNotNull()); - scopes.put("byId", byId); - - return this.render("Update", scopes); - } - - private String addDeleteByIdStatement() { - if (this.checkStatement(ResidentStatementName.DELETE_BY_ID) || null == this.persistentEntity.getIdClass()) { - return ""; - } - - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.DELETE_BY_ID); - scopes.put("parameterType", this.persistentEntity.getIdClass().getName()); - scopes.put("table", this.getTableName()); - return this.render("DeleteById", scopes); - } - - private String addDeleteByIdsStatement() { - if (this.checkStatement(ResidentStatementName.DELETE_BY_IDS)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.DELETE_BY_IDS); - scopes.put("table", this.getTableName()); - return this.render("DeleteByIds", scopes); - } - - private String addDeleteAllStatement() { - if (this.checkStatement(ResidentStatementName.DELETE_ALL)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.DELETE_ALL); - scopes.put("table", this.getTableName()); - return this.render("DeleteAll", scopes); - } - - private String addGetByIdStatement() { - if (this.checkStatement(ResidentStatementName.GET_BY_ID) || null == this.persistentEntity.getIdClass()) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.GET_BY_ID); - scopes.put("table", this.getTableName()); - scopes.put("parameterType", this.persistentEntity.getIdClass().getName()); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - return this.render("GetById", scopes); - } - - private String addFindStatement(boolean pageable) { - if (this.checkStatement(((pageable) ? ResidentStatementName.FIND_BY_PAGER : ResidentStatementName.FIND))) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", pageable ? ResidentStatementName.FIND_BY_PAGER : ResidentStatementName.FIND); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - scopes.put("table", this.getTableName()); - scopes.put("pageable", pageable); - if (pageable) { - scopes.put("limitHandler", this.limitHandler()); - scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class); - scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class); - } - scopes.put("conditionQuery", this.buildByConditionQueryCondition()); - return this.render("Find", scopes); - } - - private String addCountAllStatement() { - if (this.checkStatement(ResidentStatementName.COUNT_ALL)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.COUNT_ALL); - scopes.put("table", this.getTableName()); - return this.render("CountAll", scopes); - } - - private String addCountStatement() { - if (this.checkStatement(ResidentStatementName.COUNT)) { - return ""; - } - - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.COUNT); - scopes.put("table", this.getTableName()); - scopes.put("conditionQuery", this.buildByConditionQueryCondition()); - - return this.render("Count", scopes); - } - - private String addQueryByExample() { - if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.QUERY_BY_EXAMPLE); - scopes.put("table", this.getTableName()); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - return this.render("QueryByExample", scopes); - } - - private String addQueryByExampleForPage() { - if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE); - scopes.put("table", this.getTableName()); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - scopes.put("limitHandler", this.limitHandler()); - scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class); - scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class); - return this.render("QueryByExampleForPage", scopes); - } - - private String addCountQueryByExample() { - if (this.checkStatement(ResidentStatementName.COUNT_QUERY_BY_EXAMPLE)) { - return ""; - } - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.COUNT_QUERY_BY_EXAMPLE); - scopes.put("table", this.getTableName()); - return this.render("CountQueryByExample", scopes); - } - - private String addFindByExampleStatement() { - if (this.configuration.hasStatement(this.namespace + '.' + ResidentStatementName.FIND_BY_EXAMPLE, false)) { - return ""; - } - - Map scopes = new HashMap<>(); - scopes.put("statementName", ResidentStatementName.FIND_BY_EXAMPLE); - scopes.put("tableName", this.getTableName()); - scopes.put("entityType", this.persistentEntity.getType().getName()); - scopes.put("resultMap", ResidentStatementName.RESULT_MAP); - - return this.render("FindByExample", scopes); - } - - private String addFindByExampleWhereClauseSQL() { - if (this.configuration.getSqlFragments().containsKey(this.namespace + ".__example_where_clause")) { - return ""; - } - return this.render("FindByExampleWhereClause", null); - } - - Mustache.Lambda limitHandler() { - return (frag, out) -> out - .write(this.dialect.getLimitHandler().processSql(frag.execute(), new RowSelection(true))); - } - - Mustache.Lambda lambdaRegexLike() { - return (frag, out) -> { - String[] split = frag.execute().trim().split(";;;"); - out.write(this.dialect.getRegexLikeFunction(split[0].trim(), split[1].trim())); - }; - } - - Mustache.Lambda lambdaReplaceDotToUnderline() { - return (frag, out) -> out.write(frag.execute().trim().replace('.', '_')); - } - - Mustache.InvertibleLambda lambdaTestNotNull() { - return new InvertibleLambda() { - @Override - public void execute(Fragment frag, Writer out) throws IOException { - out.write(this.testClause(frag.execute().trim(), true, true)); - } - - @Override - public void executeInverse(Fragment frag, Writer out) throws IOException { - out.write(this.testClause(frag.execute().trim(), false, false)); - } - - protected String testClause(String propertyName, boolean and, boolean not) { - String[] parts = propertyName.split("\\."); - String[] conditions = new String[parts.length]; - String prev = null; - for (int i = 0; i < parts.length; i++) { - conditions[i] = ((null != prev) ? (prev + ".") : "") + parts[i]; - prev = conditions[i]; - } - String test = Stream.of(conditions).map(c -> c.trim() + (not ? " !" : " =") + "= null") - .collect(Collectors.joining(and ? " and " : " or ")); - return test; - } - }; - } - - private ColumnResult columnResult(MybatisPersistentProperty p) { - Column column = p.getColumn(); - ColumnResult cr = new ColumnResult(); - cr.setPrimaryKey(p.isIdProperty()); - cr.setColumn(column.getName().render(this.dialect)); - cr.setProperty(p.getName()); - cr.setJavaType(column.getJavaTypeString()); - cr.setJdbcType(column.getJdbcTypeString()); - cr.setTypeHandler(column.getTypeHandlerString()); - return cr; - } - - @Deprecated - private String buildByConditionQueryCondition() { - - String sql = this.findProperties().stream().map(pp -> { - Set set = new HashSet<>(); - Conditions conditions = pp.findAnnotation(Conditions.class); - if (null != conditions && conditions.value().length > 0) { - set.addAll(Arrays.asList(conditions.value())); - } - Condition condition = pp.findAnnotation(Condition.class); - if (null != condition) { - set.add(condition); - } - if (set.isEmpty()) { - return ""; - } - - return set.stream().map(c -> { - String[] properties = c.properties(); - if (properties.length == 0) { - properties = new String[] { pp.getName() }; - } - - Part.Type type = Part.Type.valueOf(c.type().name()); - if (type.getNumberOfArguments() > 0 && type.getNumberOfArguments() != properties.length) { - throw new MappingException("@Condition with type " + type + " needs " + type.getNumberOfArguments() - + " arguments, but only find " + properties.length + " properties in this @Condition."); - } - String cond = Stream.of(properties).map(property -> String.format("__condition.%s != null", property)) - .collect(Collectors.joining(" AND ")); - Part.IgnoreCaseType ignoreCaseType = Part.IgnoreCaseType.valueOf(c.ignoreCaseType().name()); - String columnName = StringUtils.hasText(c.column()) ? c.column() - : pp.getColumn().getName().render(this.dialect); - String left = this.buildQueryByConditionLeftSegment(columnName, ignoreCaseType, pp); - String operator = this.buildQueryByConditionOperator(type); - String right = this.buildQueryByConditionRightSegment(type, ignoreCaseType, properties, pp.getColumn()); - return String.format(" AND %s %s %s", cond, left, operator, right); - }).collect(Collectors.joining()); - }).collect(Collectors.joining()); - return String.format("%s", sql); - } - -} diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java index 600c669acd6dcbeac8713ef22326c460f65a99aa..0efac4cbc7770a9ca1520aa13cf8e3739aefab65 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java @@ -30,8 +30,9 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; * MyBatis {@link Query} from it. * * @author JARVIS SONG + * @since 2.0.0 */ -final class SimpleMybatisQuery extends AbstractStringBasedMybatisQuery { +public class SimpleMybatisQuery extends AbstractStringBasedMybatisQuery { SimpleMybatisQuery(SqlSessionTemplate sqlSessionTemplate, MybatisQueryMethod method, String queryString, String countQueryString, QueryMethodEvaluationContextProvider evaluationContextProvider, diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java index a8e162f60975581ab5a5d591193535919ef4c427..a6b3022445a38d314cb673b98968005b232e1012 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java @@ -39,8 +39,9 @@ import org.springframework.util.StringUtils; * replacing SpEL expressions with synthetic bind parameters. * * @author JARVIS SONG + * @since 2.0.0 */ -class StringQuery implements DeclaredQuery { +public class StringQuery implements DeclaredQuery { private final String query; @@ -54,7 +55,7 @@ class StringQuery implements DeclaredQuery { private final boolean usesJdbcStyleParameters; - StringQuery(String query) { + public StringQuery(String query) { Assert.hasText(query, "Query must not be null or empty!"); @@ -395,7 +396,7 @@ class StringQuery implements DeclaredQuery { } - static class ParameterBinding { + public static class ParameterBinding { private final @Nullable String name; @@ -435,7 +436,7 @@ class StringQuery implements DeclaredQuery { return this.name; } - String getRequiredName() throws IllegalStateException { + public String getRequiredName() throws IllegalStateException { String name = this.getName(); @@ -447,11 +448,11 @@ class StringQuery implements DeclaredQuery { } @Nullable - Integer getPosition() { + public Integer getPosition() { return this.position; } - int getRequiredPosition() throws IllegalStateException { + public int getRequiredPosition() throws IllegalStateException { Integer position = this.getPosition(); @@ -510,7 +511,7 @@ class StringQuery implements DeclaredQuery { } - static class InParameterBinding extends ParameterBinding { + public static class InParameterBinding extends ParameterBinding { InParameterBinding(String name, @Nullable String expression) { super(name, null, expression); @@ -539,7 +540,7 @@ class StringQuery implements DeclaredQuery { } - static class LikeParameterBinding extends ParameterBinding { + public static class LikeParameterBinding extends ParameterBinding { private static final List SUPPORTED_TYPES = Arrays.asList(Part.Type.CONTAINING, Part.Type.STARTING_WITH, Part.Type.ENDING_WITH, Part.Type.LIKE); diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java index f1688e491359b80ec34b554c82d4ae5374bc7ae0..9e5594f9f37355f24c0601b42745b63dec484ee2 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java @@ -18,6 +18,7 @@ package org.springframework.data.mybatis.repository.support; import org.springframework.data.mybatis.mapping.MybatisMappingContext; import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; +import org.springframework.data.mybatis.mapping.model.Model; import org.springframework.util.Assert; /** @@ -34,11 +35,15 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity private final MybatisPersistentEntity entity; + private final Model model; + public MybatisMappingContextEntityInformation(Class domainClass, MybatisMappingContext mappingContext) { super(domainClass); Assert.notNull(mappingContext, "MappingContext must not be null."); - this.entity = mappingContext.getRequiredPersistentEntity(domainClass); + // this.entity = mappingContext.getRequiredPersistentEntity(domainClass); + this.model = mappingContext.getRequiredModel(domainClass); + this.entity = this.model.getMappingEntity(); } @@ -48,7 +53,7 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity @Override public boolean hasCompositeId() { - return this.entity.hasCompositeId(); + return this.entity.isCompositePrimaryKey(); } @Override @@ -74,7 +79,7 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity @Override public String getTableName() { - return this.entity.getTable().getFullName(); + return this.model.getTable().toString(); } @Override @@ -93,10 +98,7 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity return super.isNew(entity); } Object version = this.entity.getPropertyAccessor(entity).getProperty(this.entity.getRequiredVersionProperty()); - if (null == version) { - return true; - } - return false; + return null == version; } } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java index 4d0d77dcd39b459999fafd732fcad0398cde7c54..bfc345a10d6c8c054911de3e005052c363730307 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java @@ -24,13 +24,11 @@ import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.BeanFactory; import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.mapping.MybatisMappingContext; +import org.springframework.data.mybatis.precompiler.MybatisQueryPrepareProcessor; import org.springframework.data.mybatis.repository.MybatisExampleRepository; import org.springframework.data.mybatis.repository.query.EscapeCharacter; import org.springframework.data.mybatis.repository.query.MybatisQueryLookupStrategy; -import org.springframework.data.mybatis.repository.query.MybatisQueryPrepareProcessor; -import org.springframework.data.mybatis.repository.query.MybatisRepositoryPrepareProcessor; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.querydsl.EntityPathResolver; import org.springframework.data.querydsl.QuerydslPredicateExecutor; @@ -58,19 +56,12 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport { private final MybatisMappingContext mappingContext; - private final SqlSessionTemplate sqlSessionTemplate; - - private final Dialect dialect; - private EntityPathResolver entityPathResolver; private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT; - public MybatisRepositoryFactory(MybatisMappingContext mappingContext, SqlSessionTemplate sqlSessionTemplate, - Dialect dialect) { + public MybatisRepositoryFactory(MybatisMappingContext mappingContext) { this.mappingContext = mappingContext; - this.sqlSessionTemplate = sqlSessionTemplate; - this.dialect = dialect; this.entityPathResolver = SimpleEntityPathResolver.INSTANCE; this.addRepositoryProxyPostProcessor((factory, repositoryInformation) -> { @@ -79,11 +70,7 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport { } }); - this.addRepositoryProxyPostProcessor( - new MybatisRepositoryPrepareProcessor(mappingContext, sqlSessionTemplate.getConfiguration(), dialect)); - this.addQueryCreationListener( - new MybatisQueryPrepareProcessor(mappingContext, sqlSessionTemplate.getConfiguration(), dialect)); - + this.addQueryCreationListener(new MybatisQueryPrepareProcessor(mappingContext)); } private static boolean hasMethodReturningStream(Class repositoryClass) { @@ -107,7 +94,8 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport { @Override protected final MybatisRepositoryImplementation getTargetRepository(RepositoryInformation metadata) { - MybatisRepositoryImplementation repository = this.getTargetRepository(metadata, this.sqlSessionTemplate); + MybatisRepositoryImplementation repository = this.getTargetRepository(metadata, + this.mappingContext.getSqlSessionTemplate()); repository.setEscapeCharacter(this.escapeCharacter); return repository; } @@ -138,8 +126,8 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport { @Override protected Optional getQueryLookupStrategy(@Nullable QueryLookupStrategy.Key key, QueryMethodEvaluationContextProvider evaluationContextProvider) { - return Optional.of(MybatisQueryLookupStrategy.create(this.sqlSessionTemplate, this.mappingContext, key, - evaluationContextProvider, this.escapeCharacter)); + return Optional.of(MybatisQueryLookupStrategy.create(this.mappingContext, key, evaluationContextProvider, + this.escapeCharacter)); } @Override @@ -160,8 +148,7 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport { .getEntityInformation(metadata.getDomainType()); Object querydslFragment = this.getTargetRepositoryViaReflection(QuerydslMybatisPredicateExecutor.class, - entityInformation, this.entityPathResolver, this.mappingContext, this.sqlSessionTemplate, - this.dialect); + entityInformation, this.entityPathResolver, this.mappingContext); fragments = fragments.append(RepositoryFragment.implemented(querydslFragment)); } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java index 77b3fc07d004ccf708ee3dd1c46d01119f847b18..8226f050f04770329369ca4da812b2b0a5eab1a2 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java @@ -15,12 +15,9 @@ */ package org.springframework.data.mybatis.repository.support; -import org.mybatis.spring.SqlSessionTemplate; - import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.mapping.MybatisMappingContext; import org.springframework.data.mybatis.repository.query.EscapeCharacter; import org.springframework.data.querydsl.EntityPathResolver; @@ -44,12 +41,8 @@ import org.springframework.util.Assert; public class MybatisRepositoryFactoryBean, S, ID> extends TransactionalRepositoryFactoryBeanSupport { - private @Nullable SqlSessionTemplate sqlSessionTemplate; - private @Nullable MybatisMappingContext mappingContext; - private @Nullable Dialect dialect; - private EntityPathResolver entityPathResolver; private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT; @@ -66,23 +59,19 @@ public class MybatisRepositoryFactoryBean, S, ID> @Override public void afterPropertiesSet() { Assert.state(null != this.mappingContext, "MybatisMappingContext must not be null!"); - Assert.state(null != this.sqlSessionTemplate, "SqlSessionTemplate must not be null!"); super.afterPropertiesSet(); } @Override protected RepositoryFactorySupport doCreateRepositoryFactory() { - return this.createRepositoryFactory(this.mappingContext, this.sqlSessionTemplate, this.dialect); + return this.createRepositoryFactory(this.mappingContext); } - private RepositoryFactorySupport createRepositoryFactory(MybatisMappingContext mappingContext, - SqlSessionTemplate sqlSessionTemplate, Dialect dialect) { + private RepositoryFactorySupport createRepositoryFactory(MybatisMappingContext mappingContext) { Assert.state(null != this.mappingContext, "MybatisMappingContext must not be null!"); - Assert.state(null != this.sqlSessionTemplate, "SqlSessionTemplate must not be null!"); - MybatisRepositoryFactory repositoryFactory = new MybatisRepositoryFactory(mappingContext, sqlSessionTemplate, - dialect); + MybatisRepositoryFactory repositoryFactory = new MybatisRepositoryFactory(mappingContext); repositoryFactory.setEntityPathResolver(this.entityPathResolver); repositoryFactory.setEscapeCharacter(this.escapeCharacter); return repositoryFactory; @@ -98,17 +87,9 @@ public class MybatisRepositoryFactoryBean, S, ID> this.escapeCharacter = EscapeCharacter.of(escapeCharacter); } - public void setSqlSessionTemplate(@Nullable SqlSessionTemplate sqlSessionTemplate) { - this.sqlSessionTemplate = sqlSessionTemplate; - } - @Autowired public void setEntityPathResolver(ObjectProvider resolver) { this.entityPathResolver = resolver.getIfAvailable(() -> SimpleEntityPathResolver.INSTANCE); } - public void setDialect(@Nullable Dialect dialect) { - this.dialect = dialect; - } - } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java index e982aa48d4e7e3fcc21d8aa68e6eeddfe18bce17..c860a42db58edda2b30396b778682746d744ee13 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java @@ -43,7 +43,6 @@ import org.mybatis.spring.SqlSessionTemplate; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; -import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.dialect.H2Dialect; @@ -54,16 +53,16 @@ import org.springframework.data.mybatis.dialect.SQLServer2012Dialect; import org.springframework.data.mybatis.dialect.SQLServerDialect; import org.springframework.data.mybatis.dialect.SQLiteDialect; import org.springframework.data.mybatis.mapping.MybatisMappingContext; -import org.springframework.data.mybatis.mapping.MybatisPersistentEntity; -import org.springframework.data.mybatis.mapping.MybatisPersistentProperty; import org.springframework.data.mybatis.mapping.handler.DateUnixTimestampTypeHandler; import org.springframework.data.mybatis.mapping.handler.UnixTimestampDateTypeHandler; import org.springframework.data.mybatis.mapping.model.Column; +import org.springframework.data.mybatis.mapping.model.Model; import org.springframework.data.mybatis.querydsl.MybatisSQLQuery; import org.springframework.data.mybatis.querydsl.type.DateAsLongType; import org.springframework.data.mybatis.querydsl.type.LongAsDateType; import org.springframework.data.querydsl.QSort; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; /** * . @@ -122,21 +121,20 @@ public class Querydsl { } this.configuration = new Configuration(sqlTemplates); - MybatisPersistentEntity entity = mappingContext.getRequiredPersistentEntity(entityInformation.getJavaType()); - entity.doWithProperties((PropertyHandler) property -> { - Column column = property.getColumn(); - if (null == column.getTypeHandler()) { - return; - } - if (column.getTypeHandler() == DateUnixTimestampTypeHandler.class) { - this.configuration.register(entity.getTable().getName().getText(), column.getName().getText(), - new DateAsLongType()); - } - if (column.getTypeHandler() == UnixTimestampDateTypeHandler.class) { - this.configuration.register(entity.getTable().getName().getText(), column.getName().getText(), - new LongAsDateType()); - } - }); + Model model = mappingContext.getRequiredModel(entityInformation.getJavaType()); + List columns = model.findColumnByTypeHandler(DateUnixTimestampTypeHandler.class); + if (!CollectionUtils.isEmpty(columns)) { + DateAsLongType dateAsLongType = new DateAsLongType(); + columns.stream().forEach(c -> this.configuration.register(model.getTable().getName().getText(), + c.getName().getText(), dateAsLongType)); + } + columns = model.findColumnByTypeHandler(UnixTimestampDateTypeHandler.class); + if (!CollectionUtils.isEmpty(columns)) { + LongAsDateType longAsDateType = new LongAsDateType(); + columns.stream().forEach(c -> this.configuration.register(model.getTable().getName().getText(), + c.getName().getText(), longAsDateType)); + } + } public AbstractSQLQuery> createQuery() { diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java index d89b57f9eff6e9a337f69c92111b2330593fa132..93ea3390d0c749acf19354e4a2a508e7d646ea87 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java @@ -24,13 +24,11 @@ import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.PathBuilder; import com.querydsl.sql.AbstractSQLQuery; -import org.mybatis.spring.SqlSessionTemplate; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.data.mybatis.dialect.Dialect; import org.springframework.data.mybatis.mapping.MybatisMappingContext; import org.springframework.data.mybatis.querydsl.MybatisRelationalPathBase; import org.springframework.data.mybatis.querydsl.MybatisSQLQuery; @@ -57,10 +55,10 @@ public class QuerydslMybatisPredicateExecutor implements QuerydslPredicate private FactoryExpression bean; public QuerydslMybatisPredicateExecutor(MybatisEntityInformation entityInformation, - EntityPathResolver resolver, MybatisMappingContext mappingContext, SqlSessionTemplate sqlSessionTemplate, - Dialect dialect) { + EntityPathResolver resolver, MybatisMappingContext mappingContext) { this.path = (MybatisRelationalPathBase) resolver.createPath(entityInformation.getJavaType()); - this.querydsl = new Querydsl<>(sqlSessionTemplate, mappingContext, dialect, entityInformation, + this.querydsl = new Querydsl<>(mappingContext.getSqlSessionTemplate(), mappingContext, + mappingContext.getDialect(), entityInformation, new PathBuilder<>(this.path.getType(), this.path.getMetadata())); this.bean = this.path.projections(); } diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java index 0c49364a529fba05a25ffc1202bdc39b0360aac2..8840c405876f90269b613f63145ba97a8267f18c 100644 --- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java +++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java @@ -36,10 +36,30 @@ public final class ResidentStatementName { */ public static final String RESULT_MAP = PREFIX + "result_map"; + /** + * For __basic_result_map. + */ + public static final String BASIC_RESULT_MAP = PREFIX + "basic_result_map"; + /** * For __result_map_. */ - public static final String RESULT_MAP_PREFIX = PREFIX + "__result_map_"; + public static final String RESULT_MAP_PREFIX = PREFIX + "result_map_"; + + /** + * For __basic_column_list. + */ + public static final String BASIC_COLUMN_LIST = PREFIX + "basic_column_list"; + + /** + * For __from. + */ + public static final String FROM = PREFIX + "from"; + + /** + * For __select. + */ + public static final String SELECT = PREFIX + "select"; /** * For __get_by_id. @@ -56,6 +76,11 @@ public final class ResidentStatementName { */ public static final String COUNT_ALL = PREFIX + "count_all"; + /** + * For __delete. + */ + public static final Object DELETE = PREFIX + "delete"; + /** * For __delete_by_id. */ @@ -191,6 +216,16 @@ public final class ResidentStatementName { */ public static final String BASE_COLUMN_LIST = PREFIX + "base_column_list"; + /** + * For __all_column_list. + */ + public static final String ALL_COLUMN_LIST = PREFIX + "all_column_list"; + + /** + * For __column_list. + */ + public static final String COLUMN_LIST = PREFIX + "column_list"; + public static String statementName(String namespace, String statement) { return namespace + '.' + statement; } diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd index 7191835bd0f22803350bc5b0811257edf38f3cc6..c65359095175a0ad9944585457544f577eb331c7 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd @@ -11,6 +11,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -36,9 +69,7 @@ - + type="org.springframework.data.mybatis.auditing.MybatisAuditingHandler"/> @@ -58,6 +89,18 @@ + + + + + + + + + + + + + {{#domain}} + {{#primaryKey}}{{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}{{/primaryKey}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{#embeddedDomains}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{/embeddedDomains}} + {{#oneToOneAssociations}} + {{#leftJoin}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{/leftJoin}} + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + {{#leftJoin}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{/leftJoin}} + {{/manyToOneAssociations}} + {{/domain}} + + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeDelete.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeDelete.mustache new file mode 100644 index 0000000000000000000000000000000000000000..62c74f142587371709802db656f0c193caa6871e --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeDelete.mustache @@ -0,0 +1,14 @@ + + {{#ass}} + {{#joinTable}}DELETE {{table}} + + {{#joinColumns}} + AND {{local.name}} = #{ {{local.name}} } + {{/joinColumns}} + {{#inverseJoinColumns}} + AND {{local.name}} = #{ {{local.name}} } + {{/inverseJoinColumns}} + + {{/joinTable}} + {{/ass}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeInsert.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeInsert.mustache new file mode 100644 index 0000000000000000000000000000000000000000..45cda9ca28f84f6a2d2ab9c9f699fd868c6df932 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeInsert.mustache @@ -0,0 +1,11 @@ + + {{#ass}} + {{#joinTable}}INSERT INTO {{table}} ( + {{#joinColumns}}{{^-first}}, {{/-first}}{{local.name}}{{/joinColumns}} + {{#inverseJoinColumns}}, {{local.name}}{{/inverseJoinColumns}} + ) VALUES ( + {{#joinColumns}}{{^-first}}, {{/-first}}#{ {{local.name}} }{{/joinColumns}} + {{#inverseJoinColumns}}, #{ {{local.name}} }{{/inverseJoinColumns}} + ){{/joinTable}} + {{/ass}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeUpdate.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeUpdate.mustache new file mode 100644 index 0000000000000000000000000000000000000000..f4760aa12780e9b82df6540f2b6a23a58b15d3de --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeUpdate.mustache @@ -0,0 +1,17 @@ + + {{#ass}} + {{#joinTable}}UPDATE {{table}} + SET + {{#joinColumns}}{{^-first}}, {{/-first}}{{local.name}} = #{ {{local.name}} }{{/joinColumns}} + {{#inverseJoinColumns}}{{local.name}} = #{ {{local.name}} }{{/inverseJoinColumns}} + + {{#joinColumns}} + AND {{local.name}} = #{ {{local.name}} } + {{/joinColumns}} + {{#inverseJoinColumns}} + AND {{local.name}} = #{ {{local.name}} } + {{/inverseJoinColumns}} + + {{/joinTable}} + {{/ass}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicColumnList.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicColumnList.mustache new file mode 100644 index 0000000000000000000000000000000000000000..50c38d11d1e21e821eb8a0157af3124619864930 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicColumnList.mustache @@ -0,0 +1,14 @@ + + + {{#domain}} + {{#primaryKey}}{{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}{{/primaryKey}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{#embeddedDomains}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{/embeddedDomains}} + {{#manyToOneAssociations}} + {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}} + {{/manyToOneAssociations}} + {{/domain}} + + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicResultMap.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicResultMap.mustache new file mode 100644 index 0000000000000000000000000000000000000000..283af95cddbd90a135a088def4a57b7ca0e824a8 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicResultMap.mustache @@ -0,0 +1,32 @@ +{{#domain}} + +{{#primaryKey}}{{#columns}} + +{{/columns}}{{/primaryKey}} +{{#columns}} + +{{/columns}} +{{#embeddedDomains}} + + {{#primaryKey}} + + {{/primaryKey}} + {{#columns}} + + {{/columns}} + +{{/embeddedDomains}} +{{#manyToOneAssociations}} + + +{{/manyToOneAssociations}} +{{#oneToOneAssociations}} + + +{{/oneToOneAssociations}} +{{#oneToManyAssociations}} + + +{{/oneToManyAssociations}} + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ColumnList.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ColumnList.mustache new file mode 100644 index 0000000000000000000000000000000000000000..eb692e6fc71ca17257f01d59cc49f9a10e795c8e --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ColumnList.mustache @@ -0,0 +1,26 @@ + + + {{#domain}} + {{#primaryKey}}{{#columns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/columns}}{{/primaryKey}} + {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}} + {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}} + {{#embeddings}} + {{#primaryKey}}{{#columns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/columns}}{{/primaryKey}} + {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}} + {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}} + {{/embeddings}} + {{#manyToOneAssociations}} + {{#leftJoin}} + {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}} + {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}} + {{#embeddings}} + {{#primaryKey}}{{#columns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/columns}}{{/primaryKey}} + {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}} + {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}} + {{/embeddings}} + {{/leftJoin}} + {{^leftJoin}}{{#foreignKey}}{{#columns}}{{#local}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{name}}{{/quote}}, {{/local}}{{/columns}}{{/foreignKey}}{{/leftJoin}} + {{/manyToOneAssociations}} + {{/domain}} + + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache index 9f49736b079e620477c086fcddaff509ac2e9f09..3c32a507a7a9c742260ac16d7d6da94ea90ff157 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache @@ -1,4 +1,3 @@ diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache index ab3acdf402695271c3599ee4f728dc82d149bbe5..d79dd422cd7fe503604eaaadecbd36368f8fa1b0 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache @@ -1 +1,5 @@ - + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache index 35b3f87b5c3425315ee2c27725c0eeaef3d52cb1..f037bef992e3bf5377818f3d4cdf7ec1b7099977 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache @@ -1,4 +1,4 @@ diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache index 4b880b7bd90eee51b97c4734155d8d7f3cc6f412..5e59032fc7d8d3b5d51049f8408f94416683e504 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache @@ -1,3 +1,5 @@ - - DELETE FROM {{table}} - +{{#domain}} + + DELETE FROM {{table}} + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache index 0be7c37d92fc266f132670c966bdff0629476bba..98e761b3d814c292868e36459f863c3f7f81544d 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache @@ -1,6 +1,12 @@ - - DELETE FROM {{table}} - - - - +{{#domain}}{{#primaryKey}} + + DELETE FROM {{table}} + + {{#columns}} + AND {{name}} = {{#composited}}#{ {{property.name}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }{{/composited}} + {{^composited}}#{_parameter}{{/composited}} + {{/columns}} + + +{{/primaryKey}} +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache index 857a065c9c9ba310499a4631ef45b2fb0fde4ebd..a9a1bc7431f6d9e9525eb6113d58479614c4ae97 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache @@ -1,6 +1,33 @@ - - DELETE FROM {{table}} - - - - +{{#domain}} + + DELETE FROM {{table}} + + + + {{#primaryKey}} + {{^composited}} + {{#columns}} + {{name}} IN + + #{item} + + {{/columns}} + {{/composited}} + {{#composited}} + + {{#columns}} + {{^-first}} AND {{/-first}} + {{name}} = #{ item.{{property.name}} } + {{/columns}} + + {{/composited}} + {{/primaryKey}} + + + + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache index 013901b89c927f7b7ae7e31ee1597f43f5b0edce..47d7346e83cebb9157cfee3f25f21f0332ee2d86 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache @@ -1,57 +1,8 @@ diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find2.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find2.mustache new file mode 100644 index 0000000000000000000000000000000000000000..013901b89c927f7b7ae7e31ee1597f43f5b0edce --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find2.mustache @@ -0,0 +1,57 @@ + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/FindByPage.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/FindByPage.mustache new file mode 100644 index 0000000000000000000000000000000000000000..56f7589f6a752e0ea55e552dd5f71d7fc281869f --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/FindByPage.mustache @@ -0,0 +1,48 @@ + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/From.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/From.mustache new file mode 100644 index 0000000000000000000000000000000000000000..36866137c4dcea631c27fbf6f2f58a04901c5afb --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/From.mustache @@ -0,0 +1,21 @@ + +{{#domain}} + {{table}} {{#quote}}{{tableAlias}}{{/quote}} + {{#oneToOneAssociations}} + {{#leftJoin}} + LEFT JOIN {{table}} {{#quote}}{{tableAlias}}{{/quote}} ON + {{#foreignKey}} + {{#columns}}{{#local}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/local}} = {{#foreign}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/foreign}}{{/columns}} + {{/foreignKey}} + {{/leftJoin}} + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + {{#leftJoin}} + LEFT JOIN {{table}} {{#quote}}{{tableAlias}}{{/quote}} ON + {{#foreignKey}} + {{#columns}}{{#local}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/local}} = {{#foreign}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/foreign}}{{/columns}} + {{/foreignKey}} + {{/leftJoin}} + {{/manyToOneAssociations}} +{{/domain}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache index 49b03ee99a969c7748a00059fa8dbb5c8edc27d8..6e59a5c73ecd3bcf17a14b4111f641ceb1a2192a 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache @@ -1,7 +1,10 @@ - +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache index b386abd4b8fa51caec8d352ca8b13f87eaf4e63b..da176d6e7c70c9036e3dce5a395db248090c3309 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache @@ -1,42 +1,74 @@ - - {{#useGeneratedKeys}} - {{keySql}} - {{/useGeneratedKeys}} - INSERT INTO {{table}} - - {{#properties}} - {{#selective}} - - {{/selective}} - {{^excludeId}} - {{value.name}}, - {{/excludeId}} - {{#excludeId}} - {{^value.primaryKey}}{{value.name}},{{/value.primaryKey}} - {{/excludeId}} - {{#selective}}{{/selective}} - {{/properties}} - - - {{#properties}} - {{#selective}} - - {{/selective}} - {{^excludeId}} - #{ {{key}}{{#value.jdbcType}} - ,jdbcType={{value.jdbcType}}{{/value.jdbcType}}{{#value.typeHandler}} - ,typeHandler={{value.typeHandler.name}}{{/value.typeHandler}} }, - {{/excludeId}} - {{#excludeId}} - {{^value.primaryKey}}#{ {{key}}{{#value.jdbcType}} - ,jdbcType={{value.jdbcType}}{{/value.jdbcType}}{{#value.typeHandler}} - ,typeHandler={{value.typeHandler.name}}{{/value.typeHandler}} - },{{/value.primaryKey}} - {{/excludeId}} - {{#selective}}{{/selective}} - {{/properties}} - - +{{#domain}} + + {{#primaryKey}} + {{#generatedKeys}} + {{#columns}} + {{keySql}} + {{/columns}} + {{/generatedKeys}} + {{/primaryKey}} + INSERT INTO {{table}} + + {{#primaryKey}} + {{^excludeInsertId}} + {{#columns}}{{name}},{{/columns}} + {{/excludeInsertId}} + {{/primaryKey}} + {{#normalColumns}}{{name}},{{/normalColumns}} + {{#versionColumns}}{{name}},{{/versionColumns}} + {{#embeddings}} + + {{#primaryKey}}{{#columns}}{{name}},{{/columns}}{{/primaryKey}} + {{#normalColumns}}{{name}},{{/normalColumns}} + {{#verionColumns}}{{name}},{{/verionColumns}} + + {{/embeddings}} + {{#oneToOneAssociations}} + + {{#foreignKey}} + {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}} + {{/foreignKey}} + + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + + {{#foreignKey}} + {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}} + {{/foreignKey}} + + {{/manyToOneAssociations}} + + + {{#primaryKey}} + {{^excludeInsertId}} + {{#columns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/columns}} + {{/excludeInsertId}} + {{/primaryKey}} + {{#normalColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/normalColumns}} + {{#versionColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/versionColumns}} + {{#embeddings}} + + {{#primaryKey}}{{#columns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/columns}}{{/primaryKey}} + {{#normalColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/normalColumns}} + {{#versionColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/versionColumns}} + + {{/embeddings}} + {{#oneToOneAssociations}} + + {{#foreignKey}} + {{#columns}}{{#foreign}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/foreign}}{{/columns}} + {{/foreignKey}} + + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + + {{#foreignKey}} + {{#columns}}{{#foreign}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/foreign}}{{/columns}} + {{/foreignKey}} + + {{/manyToOneAssociations}} + + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/InsertSelective.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/InsertSelective.mustache new file mode 100644 index 0000000000000000000000000000000000000000..c642fc53761391769596340f5973a100cd765887 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/InsertSelective.mustache @@ -0,0 +1,136 @@ +{{#domain}} + + {{#primaryKey}} + {{#generatedKeys}} + {{#columns}} + {{keySql}} + {{/columns}} + {{/generatedKeys}} + {{/primaryKey}} + INSERT INTO {{table}} + + {{#primaryKey}} + {{^excludeInsertId}} + {{#columns}} + + {{name}}, + {{/columns}} + {{/excludeInsertId}} + {{/primaryKey}} + {{#normalColumns}} + {{name}}, + {{/normalColumns}} + {{#versionColumns}} + {{name}}, + {{/versionColumns}} + {{#embeddings}} + {{#primaryKey}} + {{#columns}} + + {{name}}, + + {{/columns}} + {{/primaryKey}} + {{#normalColumns}} + + {{name}}, + + {{/normalColumns}} + {{#versionColumns}} + + {{name}}, + + {{/versionColumns}} + {{/embeddings}} + {{#oneToOneAssociations}} + {{#foreignKey}} + {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}} + {{/foreignKey}} + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + {{#foreignKey}} + {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}} + {{/foreignKey}} + {{/manyToOneAssociations}} + + + {{#primaryKey}} + {{^excludeInsertId}} + {{#columns}} + + #{ {{propertyName}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/columns}} + {{/excludeInsertId}} + {{/primaryKey}} + {{#normalColumns}} + + #{ {{propertyName}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/normalColumns}} + {{#versionColumns}} + + #{ {{propertyName}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/versionColumns}} + {{#embeddings}} + {{#primaryKey}} + {{#columns}} + + #{ {{propertyName}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}} + }, + + {{/columns}} + {{/primaryKey}} + {{#normalColumns}} + + #{ {{propertyName}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/normalColumns}} + {{#versionColumns}} + + #{ {{propertyName}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/versionColumns}} + {{/embeddings}} + {{#oneToOneAssociations}} + {{#foreignKey}} + {{#columns}}{{#foreign}} + + #{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/foreign}}{{/columns}} + {{/foreignKey}} + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + {{#foreignKey}} + {{#columns}}{{#foreign}} + + #{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/foreign}}{{/columns}} + {{/foreignKey}} + {{/manyToOneAssociations}} + + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Mapper.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Mapper.mustache new file mode 100644 index 0000000000000000000000000000000000000000..6a3d0f4c4c1d8992e4c2a31349844e601c74ddbe --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Mapper.mustache @@ -0,0 +1,6 @@ + + + + + {{#statements}}{{.}}{{/statements}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache index a67def57083c2dbf84870099dda84dbe0fd29258..dd6c9909d5271b79c4df6a0c5711953dcf945277 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache @@ -1,12 +1,12 @@ {{#tree}} {{^-first}} OR {{/-first}} ( - {{#parts}} + {{#this}} {{^-first}} AND {{/-first}} {{^opIn}} {{^opNotIn}} - {{#ignoreCase}}{{lowercaseFunction}}({{column.name}}){{/ignoreCase}} - {{^ignoreCase}}{{column.name}}{{/ignoreCase}} + {{#ignoreCase}}{{lowercaseFunction}}({{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}){{/ignoreCase}} + {{^ignoreCase}}{{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}{{/ignoreCase}} {{/opNotIn}} {{/opIn}} {{#opBetween}} @@ -48,18 +48,17 @@ {{#opIn}} - {{#ignoreCase}}{{lowercaseFunction}}({{column.name}}){{/ignoreCase}} - {{^ignoreCase}}{{column.name}}{{/ignoreCase}} + {{#ignoreCase}}{{lowercaseFunction}}({{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}){{/ignoreCase}} + {{^ignoreCase}}{{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}{{/ignoreCase}} IN #{__item - {{#column.hasJavaType}} - ,javaType={{column.javaTypeString}} - {{/column.hasJavaType}} - {{#column.hasTypeHandler}} - ,typeHandler={{column.typeHandlerString}} - {{/column.hasTypeHandler}} } + {{#column}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}}{{/column}} + } 0=1 @@ -68,18 +67,17 @@ {{#opNotIn}} - {{#ignoreCase}}{{lowercaseFunction}}({{column.name}}){{/ignoreCase}} - {{^ignoreCase}}{{column.name}}{{/ignoreCase}} + {{#ignoreCase}}{{lowercaseFunction}}({{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}){{/ignoreCase}} + {{^ignoreCase}}{{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}{{/ignoreCase}} NOT IN #{__item - {{#column.hasJavaType}} - ,javaType={{column.javaTypeString}} - {{/column.hasJavaType}} - {{#column.hasTypeHandler}} - ,typeHandler={{column.typeHandlerString}} - {{/column.hasTypeHandler}} } + {{#column}}{{#javaType}} + ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}} + ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}} + ,typeHandler={{typeHandler.name}}{{/typeHandler}}{{/column}} + } 0=1 @@ -102,14 +100,10 @@ {{/ignoreCase}} {{^ignoreCase}} #{ {{#arguments}}{{.}}{{/arguments}} - {{#column.hasJavaType}} - ,javaType={{column.javaTypeString}} - {{/column.hasJavaType}} - {{#column.hasTypeHandler}} - ,typeHandler={{column.typeHandlerString}} - {{/column.hasTypeHandler}} } + {{#column}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}}{{/column}} + } {{/ignoreCase}} {{/opDefault}} - {{/parts}} + {{/this}} ) {{/tree}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache index 4f378cdc482d7df6e932eb7d1c91f1127dcb5607..fe734c9c5b19b02f0612835c2ab5cd5e0662a7bf 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache @@ -1,5 +1,5 @@ - DELETE FROM {{table}} + DELETE FROM {{domain.table}} {{>PartTreeCondition}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCount.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerCount.mustache similarity index 80% rename from spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCount.mustache rename to spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerCount.mustache index 54c970dfde6fa67c82537b2793f0891ca0420b39..cc9631f9f073c9ec4cb1dc9d107a067b4058963a 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCount.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerCount.mustache @@ -1,4 +1,4 @@ - {{#limiting}} SELECT COUNT(*) FROM ( @@ -8,7 +8,7 @@ ORDER BY CURRENT_TIMESTAMP - ) AS __mybatis_row_nr__ FROM ( SELECT * FROM {{table}} + ) AS __mybatis_row_nr__ FROM ( SELECT * FROM {{>PartTreeCondition}} @@ -17,7 +17,7 @@ {{/SQLServer2005}} {{#SQLServer2012}} - SELECT * FROM {{table}} + SELECT * FROM {{>PartTreeCondition}} @@ -27,7 +27,7 @@ WITH query AS ( SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP ) AS - __mybatis_row_nr__ FROM ( SELECT * FROM {{table}} + __mybatis_row_nr__ FROM ( SELECT * FROM {{>PartTreeCondition}} @@ -37,14 +37,14 @@ {{/SQLServer2012}} {{^SQLServer2005}}{{^SQLServer2012}} {{#limitHandler}} - SELECT {{columns}} FROM {{table}} + SELECT {{columns}} FROM {{>PartTreeCondition}} {{/limitHandler}} {{/SQLServer2012}}{{/SQLServer2005}} ) __a {{/limiting}} {{^limiting}} - SELECT {{columns}} FROM {{table}} + SELECT {{columns}} FROM {{>PartTreeCondition}} {{/limiting}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeSelect.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerSelect.mustache similarity index 79% rename from spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeSelect.mustache rename to spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerSelect.mustache index 3e5fa54b5134413ddd22e666af4acf7010077a3c..d807289b00df601f2532de0e98de2adb2f54c212 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeSelect.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerSelect.mustache @@ -1,4 +1,4 @@ - - select * from {{table}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleForPage.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleForPage.mustache index e851ee820bf9da55523f88d377148c370ed81aff..6b7d5cb17cc8db3242a74f597509f711bf87eaa9 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleForPage.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleForPage.mustache @@ -5,21 +5,21 @@ ORDER BY CURRENT_TIMESTAMP - ) AS __mybatis_row_nr__ FROM ( SELECT * FROM {{table}} + ) AS __mybatis_row_nr__ FROM ( ) inner_query ) SELECT * FROM query WHERE __mybatis_row_nr__ > #{__offset} AND __mybatis_row_nr__ <= #{__offsetEnd} {{/SQLServer2005}} {{#SQLServer2012}} - SELECT * FROM {{table}} + OFFSET #{__offset} ROWS FETCH NEXT #{__pageSize} ROWS ONLY WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY - CURRENT_TIMESTAMP ) AS __mybatis_row_nr__ FROM ( SELECT * FROM {{table}} + CURRENT_TIMESTAMP ) AS __mybatis_row_nr__ FROM ( ) inner_query ) SELECT * FROM query WHERE __mybatis_row_nr__ > #{__offset} AND __mybatis_row_nr__ <= #{__offsetEnd} @@ -27,7 +27,7 @@ {{/SQLServer2012}} {{^SQLServer2005}}{{^SQLServer2012}} {{#limitHandler}} - SELECT * FROM {{table}} + {{/limitHandler}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleWhereClause.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleWhereClause.mustache index ba99093193a6f83df3f512966719037ce8309b71..f169b9f4fa7a9f2a000022bd57ef2e57da48427a 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleWhereClause.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/QueryByExampleWhereClause.mustache @@ -1,138 +1,91 @@ - + - {{#properties}} - - {{! not ignored path}} - - or - and + {{#combinedColumns}} + + + OR + AND - + - - {{dialect.lowercaseFunction}}({{value.name}}) + + {{lowercaseFunction}}({{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}) - {{value.name}} + {{#quote}}{{model.tableAlias}}{{/quote}}.{{name}} - {{^value.string}} + {{^string}} {{!not string}} = - - {{dialect.lowercaseFunction}}(#{ - __entity.{{key}} - {{#value.hasJavaType}} - ,javaType={{value.javaTypeString}} - {{/value.hasJavaType}} - {{#value.hasTypeHandler}} - ,typeHandler={{value.typeHandlerString}} - {{/value.hasTypeHandler}} - }) + + {{lowercaseFunction}}(#{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }) - #{ __entity.{{key}} - {{#value.hasJavaType}} - ,javaType={{value.javaTypeString}} - {{/value.hasJavaType}} - {{#value.hasTypeHandler}} - ,typeHandler={{value.typeHandlerString}} - {{/value.hasTypeHandler}} - } - + #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } - {{/value.string}} - {{#value.string}} + {{/string}} + {{#string}} {{!string property}} - + - + = - - {{dialect.lowercaseFunction}}(#{ __entity.{{key}} - {{#value.hasJavaType}} - ,javaType={{value.javaTypeString}} - {{/value.hasJavaType}} - {{#value.hasTypeHandler}} - ,typeHandler={{value.typeHandlerString}} - {{/value.hasTypeHandler}} - }) + + {{lowercaseFunction}}(#{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }) - #{ __entity.{{key}} - {{#value.hasJavaType}} - ,javaType={{value.javaTypeString}} - {{/value.hasJavaType}} - {{#value.hasTypeHandler}} - ,typeHandler={{value.typeHandlerString}} - {{/value.hasTypeHandler}} - } - + #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } - + LIKE - + - - {{dialect.lowercaseFunction}}(#{ - __starting_{{#replaceDotToUnderline}}{{key}}{{/replaceDotToUnderline}} - }) + + {{lowercaseFunction}}(#{ __starting_{{#replaceDotToUnderline}}{{propertyName}}{{/replaceDotToUnderline}} }) - #{ - __starting_{{#replaceDotToUnderline}}{{key}}{{/replaceDotToUnderline}} - } - + #{ __starting_{{#replaceDotToUnderline}}{{propertyName}}{{/replaceDotToUnderline}} } - + LIKE - + - - {{dialect.lowercaseFunction}}(#{ - __ending_{{#replaceDotToUnderline}}{{key}}{{/replaceDotToUnderline}} - }) + + {{lowercaseFunction}}(#{ __ending_{{#replaceDotToUnderline}}{{propertyName}}{{/replaceDotToUnderline}} }) - #{ - __ending_{{#replaceDotToUnderline}}{{key}}{{/replaceDotToUnderline}} - } - + #{ __ending_{{#replaceDotToUnderline}}{{propertyName}}{{/replaceDotToUnderline}} } - + LIKE - + - - {{dialect.lowercaseFunction}}(#{ - __containing_{{#replaceDotToUnderline}}{{key}}{{/replaceDotToUnderline}} - }) + + {{lowercaseFunction}}(#{ __containing_{{#replaceDotToUnderline}}{{propertyName}}{{/replaceDotToUnderline}} }) - #{ - __containing_{{#replaceDotToUnderline}}{{key}}{{/replaceDotToUnderline}} - } - + #{ __containing_{{#replaceDotToUnderline}}{{propertyName}}{{/replaceDotToUnderline}} } - + {{#regexLike}} - {{value.name}};;;#{ __entity.{{key}} } + {{value.name}};;;#{ __entity.{{propertyName}} } {{/regexLike}} - {{/value.string}} + {{/string}} - - or - and - {{value.name}} IS NULL + + OR + AND + {{#quote}}{{model.tableAlias}}{{/quote}}.{{name}} IS NULL - {{/properties}} + {{/combinedColumns}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMap.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMap.mustache index 1aba7e99d7959f7a4158dd2fd97c0ada1b496a57..dd9c94c6657e1c7abda96be15cc7d23000ad8f0b 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMap.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMap.mustache @@ -1,30 +1,53 @@ - - {{#results}} - <{{#primaryKey}}id{{/primaryKey}}{{^primaryKey}}result{{/primaryKey}} property="{{property}}" column="{{column}}" {{#javaType}}javaType="{{javaType}}"{{/javaType}} {{#jdbcType}}jdbcType="{{jdbcType}}"{{/jdbcType}} {{#typeHandler}} typeHandler="{{typeHandler}}"{{/typeHandler}} /> - {{/results}} - {{#embeddedAssociations}} - - {{#results}} - <{{#primaryKey}}id{{/primaryKey}}{{^primaryKey}}result{{/primaryKey}} - property="{{property}}" column="{{column}}" - {{#javaType}}javaType="{{javaType}}"{{/javaType}} - {{#jdbcType}}jdbcType="{{jdbcType}}"{{/jdbcType}} - {{#typeHandler}} typeHandler="{{typeHandler}}"{{/typeHandler}} - /> - {{/results}} - - {{/embeddedAssociations}} - {{#associations}} - - {{/associations}} - {{#collections}} - - {{/collections}} - - +{{#domain}} + + {{#primaryKey}} + {{#columns}} + + {{/columns}} + {{/primaryKey}} + {{#versionColumns}} + + {{/versionColumns}} + {{#normalColumns}} + + {{/normalColumns}} + {{#embeddings}} + + {{#primaryKey}}{{#columns}} + + {{/columns}}{{/primaryKey}} + {{#normalColumns}} + + {{/normalColumns}} + + {{/embeddings}} + {{#manyToOneAssociations}} + {{#leftJoin}} + + + {{/leftJoin}} + {{^leftJoin}} + + + {{/leftJoin}} + {{/manyToOneAssociations}} + {{#oneToOneAssociations}} + {{#leftJoin}} + + + {{/leftJoin}} + {{^leftJoin}} + + + {{/leftJoin}} + {{/oneToOneAssociations}} + {{#oneToManyAssociations}} + + + {{/oneToManyAssociations}} + {{#manyToManyAssociations}} + + + {{/manyToManyAssociations}} + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMapManyToManySelect.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMapManyToManySelect.mustache new file mode 100644 index 0000000000000000000000000000000000000000..ab5e407ff913ec989578c8e572de9e456f5b49a1 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMapManyToManySelect.mustache @@ -0,0 +1,17 @@ + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMapOneToManySelect.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMapOneToManySelect.mustache new file mode 100644 index 0000000000000000000000000000000000000000..fb45613a6e4c7dccdf27be4b1cfef90f48500526 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ResultMapOneToManySelect.mustache @@ -0,0 +1,10 @@ + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Select.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Select.mustache new file mode 100644 index 0000000000000000000000000000000000000000..4df0b1f8244dee56994f9c8754ebcf6045d52349 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Select.mustache @@ -0,0 +1,3 @@ + + SELECT FROM + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryDelete.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryDelete.mustache new file mode 100644 index 0000000000000000000000000000000000000000..85d35fdcfc232fd9a8214b054ba6b30b7ae8849e --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryDelete.mustache @@ -0,0 +1,3 @@ + + {{query}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryInsert.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryInsert.mustache new file mode 100644 index 0000000000000000000000000000000000000000..8b42a140eaabeabfb7afbe5b4832cbc60e2516d4 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryInsert.mustache @@ -0,0 +1,3 @@ + + {{query}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQuerySelect.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQuerySelect.mustache new file mode 100644 index 0000000000000000000000000000000000000000..f24def6135154d479f1767c4560668f3957d7da8 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQuerySelect.mustache @@ -0,0 +1,37 @@ +{{#hasConstructor}} + + + {{#constructorParameters}} + + {{/constructorParameters}} + + +{{/hasConstructor}} + +{{#isPageQuery}} + +{{/isPageQuery}} + +{{#isUnpagedQuery}} + + +{{/isUnpagedQuery}} + + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryUpdate.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryUpdate.mustache new file mode 100644 index 0000000000000000000000000000000000000000..52b5ba3f9a5b041bfed89ef7fefad5aa192c8857 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/SimpleQueryUpdate.mustache @@ -0,0 +1,3 @@ + + {{query}} + diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/StandardSort.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/StandardSort.mustache index 5a274de3a602f8a6579ea0931b9e32bb567f0b20..4628872208fa473354e92ac26f8ef8d8733b770c 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/StandardSort.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/StandardSort.mustache @@ -1,15 +1,14 @@ - + {{#domain}} + + {{/domain}} ORDER BY {{lowercaseFunction}}( ${__columnsMap[item.property]} - - - - ) ${item.direction.name()} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Update.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Update.mustache index c5b9eeddac0e2777c3753ed9fc06ddf92e9365bd..34ed00571ddf89cdf6cbb0e52462e104196458f9 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Update.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Update.mustache @@ -1,37 +1,77 @@ - - UPDATE {{table}} - - {{#properties}} - {{^value.primaryKey}} - {{^value.version}} - {{#selective}} - - {{/selective}} - {{value.name}} = #{ __entity.{{key}}{{#value.jdbcType}} - ,jdbcType={{value.jdbcType}}{{/value.jdbcType}}{{#value.typeHandler}} - ,typeHandler={{value.typeHandler.name}}{{/value.typeHandler}} }, - {{#selective}}{{/selective}} - {{/value.version}} - {{#value.version}} - {{value.name}} = {{value.name}} + 1, - {{/value.version}} - {{/value.primaryKey}} - {{/properties}} - - - {{#byId}} - - {{/byId}} - {{^byId}} - - {{/byId}} - {{#properties}} - {{#value.version}} - AND - {{value.name}} = #{ __entity.{{key}}{{#value.jdbcType}} - ,jdbcType={{value.jdbcType}}{{/value.jdbcType}}{{#value.typeHandler}} - ,typeHandler={{value.typeHandler.name}}{{/value.typeHandler}} } - {{/value.version}} - {{/properties}} - - +{{#domain}} + + UPDATE {{table}} + + {{#normalColumns}} + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + {{/normalColumns}} + {{#versionColumns}} + {{name}} = {{name}} + 1, + {{/versionColumns}} + {{#embeddings}} + + {{#primaryKey}} + {{#columns}} + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + {{/columns}} + {{/primaryKey}} + {{#normalColumns}} + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + {{/normalColumns}} + {{#versionColumns}} + {{name}} = {{name}} + 1, + {{/versionColumns}} + + {{/embeddings}} + {{#oneToOneAssociations}} + + {{#foreignKey}} + {{#columns}} + {{#local}} + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + {{/local}} + {{/columns}} + {{/foreignKey}} + + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + + {{#foreignKey}} + {{#columns}} + {{#local}} + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + {{/local}} + {{/columns}} + {{/foreignKey}} + + {{/manyToOneAssociations}} + + + {{^byId}} + {{#primaryKey}} + {{#columns}} + AND {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } + {{/columns}} + {{/primaryKey}} + {{/byId}} + {{#byId}} + {{#primaryKey}} + {{#columns}} + AND {{name}} = {{#composited}}#{ __id.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }{{/composited}} + {{^composited}}#{__id}{{/composited}} + {{/columns}} + {{/primaryKey}} + {{/byId}} + {{#versionColumns}} + AND {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } + {{/versionColumns}} + {{#embeddings}} + + {{#versionColumns}} + AND {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } + {{/versionColumns}} + + {{/embeddings}} + + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/UpdateSelective.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/UpdateSelective.mustache new file mode 100644 index 0000000000000000000000000000000000000000..20054ad8fca4b0c56d31d99e52da1ccf441ac7d3 --- /dev/null +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/UpdateSelective.mustache @@ -0,0 +1,81 @@ +{{#domain}} + + UPDATE {{table}} + + {{#normalColumns}} + + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/normalColumns}} + {{#versionColumns}} + {{name}} = {{name}} + 1, + {{/versionColumns}} + {{#embeddings}} + {{#primaryKey}} + {{#columns}} + + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/columns}} + {{/primaryKey}} + {{#normalColumns}} + + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/normalColumns}} + {{#versionColumns}} + {{name}} = {{name}} + 1, + {{/versionColumns}} + {{/embeddings}} + {{#oneToOneAssociations}} + {{#foreignKey}} + {{#joinColumns}} + {{#local}} + + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/local}} + {{/joinColumns}} + {{/foreignKey}} + {{/oneToOneAssociations}} + {{#manyToOneAssociations}} + {{#foreignKey}} + {{#columns}} + {{#local}} + + {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }, + + {{/local}} + {{/columns}} + {{/foreignKey}} + {{/manyToOneAssociations}} + + + {{^byId}} + {{#primaryKey}} + {{#columns}} + AND {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } + {{/columns}} + {{/primaryKey}} + {{/byId}} + {{#byId}} + {{#primaryKey}} + {{#columns}} + AND {{name}} = {{#composited}}#{ __id.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }{{/composited}} + {{^composited}}#{__id}{{/composited}} + {{/columns}} + {{/primaryKey}} + {{/byId}} + {{#versionColumns}} + AND {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } + {{/versionColumns}} + {{#embeddedDomains}} + + {{#versionColumns}} + AND {{name}} = #{ __entity.{{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} } + {{/versionColumns}} + + {{/embeddedDomains}} + + +{{/domain}} diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseById.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseById.mustache index ef2f82527f85f7e8599f646b11fb8b2105c19efd..ff3613c59a3da24038efade6bbc11063c230f54c 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseById.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseById.mustache @@ -1,15 +1,10 @@ - {{#embedded}} - {{#properties}} - AND {{column.name}} = #{ {{name}} } - {{/properties}} - {{/embedded}} - {{^embedded}} - {{#properties}} - {{#isIdProperty}} - AND {{column.name}} = #{ {{name}} } - {{/isIdProperty}} - {{/properties}} - {{/embedded}} + {{#domain}} + {{#primaryKey}} + {{#columns}} + AND {{#quote}}{{alias}}{{/quote}}.{{name}} = {{#composited}}#{ {{property.name}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }{{/composited}} + {{^composited}}#{_parameter}{{/composited}} + {{/columns}} + {{/primaryKey}} + {{/domain}} - diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseByIds.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseByIds.mustache index 9ff54436433c9bca1efa4470c705296953ad30cf..fa76bbc4eb0e32aedd54a527c8ced2c37a06a662 100644 --- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseByIds.mustache +++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/WhereClauseByIds.mustache @@ -1,23 +1,28 @@ +{{#domain}} - - {{^embedded}} - {{idProperty.column.name}} IN - - #{item} - - {{/embedded}} - {{#embedded}} - - {{#properties}} - {{^-first}} AND {{/-first}} - {{column.name}} = #{ item.{{name}} } - {{/properties}} - - {{/embedded}} + + {{#primaryKey}} + {{^composited}} + {{#columns}} + AND {{#quote}}{{tableAlias}}{{/quote}}.{{name}} IN + + #{item} + + {{/columns}} + {{/composited}} + {{#composited}} + + {{#columns}} + {{^-first}} AND {{/-first}} + {{#quote}}{{tableAlias}}{{/quote}}.{{name}} = #{ item.{{property.name}} } + {{/columns}} + + {{/composited}} + {{/primaryKey}} +{{/domain}} diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Customer.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Customer.java index 01be2f178e0f6269fd7a7dba8ac332357c1cac3f..3e6aa0a8963319ccdf2052201ffeb7e545f45235 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Customer.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Customer.java @@ -16,8 +16,8 @@ package org.springframework.data.mybatis.domain.sample; import java.io.Serializable; +import java.sql.Timestamp; import java.util.Collections; -import java.util.Date; import java.util.List; import javax.persistence.Column; @@ -80,17 +80,17 @@ public class Customer implements Serializable { @CreatedDate @Temporal(TemporalType.TIMESTAMP) - @Column(name = "creation_date") - private Date creationDate; + @Column(name = "created_date") + private Timestamp createdDate; @LastModifiedBy - @Column(name = "last_updated_by") - private Long lastUpdatedBy; + @Column(name = "last_modified_by") + private Long lastModifiedBy; @LastModifiedDate @Temporal(TemporalType.TIMESTAMP) - @Column(name = "last_update_date") - private Date lastUpdateDate; + @Column(name = "last_modified_date") + private Timestamp lastModifiedDate; @OrderBy("name desc") @ManyToMany(fetch = FetchType.EAGER) diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Goods.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Goods.java index e6e9a97283b05fa5263775487ad2e63040117c55..61e471fad832487418728482a6ac87400a673c64 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Goods.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Goods.java @@ -24,6 +24,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import org.springframework.data.mybatis.annotation.Fetch; +import org.springframework.data.mybatis.annotation.FetchMode; import org.springframework.data.mybatis.domain.Audit; /** @@ -45,10 +47,12 @@ public class Goods extends Audit { private String brand; + @Fetch(FetchMode.JOIN) @ManyToOne @JoinColumn(name = "category_id", referencedColumnName = "id") private Category category; + @Fetch(FetchMode.SELECT) @ManyToOne @JoinColumn(name = "shop_id", referencedColumnName = "id") private Shop shop; diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Person.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Person.java index 71ebe732c026bc1a099a71f68da145c96c55c713..a3b93b1e5e9ed750b08cbda37ffdab5c188930a6 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Person.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Person.java @@ -45,6 +45,9 @@ public class Person extends Audit { @Embedded private Address address; + // @OneToMany(mappedBy = "person", cascade = CascadeType.ALL) + // private Set users; + public Person(String firstname, String lastname, Address address) { this.firstname = firstname; this.lastname = lastname; diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Role.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Role.java index cff66ffc9460e1f6abeb6cfd5b64065040fdb066..86f4cd3f45b5bfb2675a4541e64ad133221e7d4f 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Role.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/Role.java @@ -39,6 +39,9 @@ public class Role extends AbstractPersistable { private String name; + // @ManyToMany(mappedBy = "roles", cascade = CascadeType.ALL) + // private List users; + public Role(String name) { this.name = name; } diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/User.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/User.java index 7926a0c3df23bdf541880ea7f981b072e05876b0..f062a6c6821d26aba348950f24f855eda3f7e91d 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/User.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/domain/sample/User.java @@ -21,6 +21,7 @@ import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @@ -32,6 +33,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import org.springframework.data.mybatis.annotation.Fetch; +import org.springframework.data.mybatis.annotation.FetchMode; import org.springframework.data.mybatis.domain.AbstractPersistable; /** @@ -51,11 +54,12 @@ public class User extends AbstractPersistable { private String email; + @Fetch(FetchMode.JOIN) @ManyToOne(cascade = CascadeType.ALL) private Person person; @OrderBy - @ManyToMany(cascade = CascadeType.ALL) + @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")) private Set roles; diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/UserRepositoryTest.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/UserRepositoryTest.java index 8bfa102d26a13590957d4111cd5f9576b4120115..038cdadf2baaa60eadce86d501558a056380e759 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/UserRepositoryTest.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/UserRepositoryTest.java @@ -109,6 +109,21 @@ public class UserRepositoryTest { this.fourth.addRoles(this.grape); this.repository.saveSelectiveAll(this.first, this.second, this.third, this.fourth); + this.repository.insertUserRole(this.first.getId(), this.apple.getId()); + this.repository.insertUserRole(this.first.getId(), this.orange.getId()); + this.repository.insertUserRole(this.first.getId(), this.banana.getId()); + this.repository.insertUserRole(this.second.getId(), this.orange.getId()); + this.repository.insertUserRole(this.second.getId(), this.banana.getId()); + this.repository.insertUserRole(this.third.getId(), this.banana.getId()); + this.repository.insertUserRole(this.third.getId(), this.grape.getId()); + this.repository.insertUserRole(this.fourth.getId(), this.grape.getId()); + } + + @Test + public void testGetById() { + this.flushUsers(); + User user = this.repository.getById(this.first.getId()); + assertThat(user).isEqualTo(this.first); } @Test diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/CustomerRepository.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/CustomerRepository.java index 50979424f885ac1d7a050fecee223c1a515f8aea..abb6e200b5d6f920966aaa97d0cca11ab1d33f88 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/CustomerRepository.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/CustomerRepository.java @@ -60,7 +60,7 @@ public interface CustomerRepository extends MybatisRepository { boolean existsByNameLastname(String lastname); - @Query("select firstname from t_customer where lastname = ?1") + @Query("select firstname from customer where lastname = ?1") List findFirstnamesByLastname(String lastname); List findAllByOrderByNameLastnameAsc(); diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepository.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepository.java index f13b248ee619ea97c4422ecf34c5ef90a1f5e61f..5a4cc9aff6bc70d48efcdbfb56c0c7b0e656a368 100644 --- a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepository.java +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepository.java @@ -25,6 +25,7 @@ import org.springframework.data.querydsl.QuerydslPredicateExecutor; * @author JARVIS SONG * @since 2.0.2 */ -public interface UserRepository extends MybatisRepository, QuerydslPredicateExecutor { +public interface UserRepository + extends MybatisRepository, UserRepositoryCustom, QuerydslPredicateExecutor { } diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepositoryCustom.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepositoryCustom.java new file mode 100644 index 0000000000000000000000000000000000000000..fad4d11e955a612e01de7282bd5613eb6a4b03cf --- /dev/null +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepositoryCustom.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-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.mybatis.repository.sample; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public interface UserRepositoryCustom { + + int insertUserRole(Long userId, Long roleId); + +} diff --git a/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepositoryImpl.java b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepositoryImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..8c0659b34629456407fbea2db5d0ef5cc0b8070c --- /dev/null +++ b/spring-data-mybatis/src/test/java/org/springframework/data/mybatis/repository/sample/UserRepositoryImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-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.mybatis.repository.sample; + +import java.util.HashMap; +import java.util.Map; + +import org.mybatis.spring.SqlSessionTemplate; + +import org.springframework.data.mybatis.domain.sample.User; +import org.springframework.data.mybatis.repository.support.ResidentStatementName; +import org.springframework.data.mybatis.repository.support.SqlSessionRepositorySupport; + +/** + * . + * + * @author JARVIS SONG + * @since 2.0.2 + */ +public class UserRepositoryImpl extends SqlSessionRepositorySupport implements UserRepositoryCustom { + + public UserRepositoryImpl(SqlSessionTemplate sqlSessionTemplate) { + super(sqlSessionTemplate); + } + + @Override + protected String getNamespace() { + return User.class.getName(); + } + + @Override + public int insertUserRole(Long userId, Long roleId) { + Map map = new HashMap<>(); + map.put("user_id", userId); + map.put("role_id", roleId); + return this.getSqlSession().insert("associative.user_role." + ResidentStatementName.INSERT, map); + } + +} diff --git a/spring-data-mybatis/src/test/resources/META-INF/mybatis-named-queries.properties b/spring-data-mybatis/src/test/resources/META-INF/mybatis-named-queries.properties index c691c7c7ba53bacd5eb610f14fc9394cc0c94aae..e73365f42ca5f9db85846295dca44fc0ca6141c5 100644 --- a/spring-data-mybatis/src/test/resources/META-INF/mybatis-named-queries.properties +++ b/spring-data-mybatis/src/test/resources/META-INF/mybatis-named-queries.properties @@ -1 +1 @@ -Customer.findBySpringDataNamedQuery=select * from t_customer where lastname=?1 +Customer.findBySpringDataNamedQuery=select * from customer where lastname=?1 diff --git a/spring-data-mybatis/src/test/resources/application-context.xml b/spring-data-mybatis/src/test/resources/application-context.xml index bedef31386956ca7c3b88a54103bde00d7e9f4c7..d54db5df39ebca51d47a6a75bdce7d44dab12cf6 100644 --- a/spring-data-mybatis/src/test/resources/application-context.xml +++ b/spring-data-mybatis/src/test/resources/application-context.xml @@ -20,7 +20,6 @@ - @@ -31,7 +30,6 @@ - - - - - - @@ -72,28 +65,19 @@ - - - - - - - - - - - - + class="org.springframework.data.mybatis.mapping.MybatisMappingContext"> + + + org.springframework.data.mybatis.domain.sample.Category + org.springframework.data.mybatis.domain.sample.Goods + org.springframework.data.mybatis.domain.sample.Customer + org.springframework.data.mybatis.domain.sample.Shop + + @@ -105,7 +89,7 @@ + class="org.springframework.data.mybatis.auditing.MybatisAuditingHandler"> diff --git a/spring-data-mybatis/src/test/resources/config/namespace-application-context.xml b/spring-data-mybatis/src/test/resources/config/namespace-application-context.xml index 7b4bf797909d95d1c0c38546dacc911b028778c8..1f8117bed0a53be9879a83fb41ed3d2a915c03b9 100644 --- a/spring-data-mybatis/src/test/resources/config/namespace-application-context.xml +++ b/spring-data-mybatis/src/test/resources/config/namespace-application-context.xml @@ -7,14 +7,20 @@ + + + - - + diff --git a/spring-data-mybatis/src/test/resources/infrastructure.xml b/spring-data-mybatis/src/test/resources/infrastructure.xml index ceafeb5b2d980c17950fe778043ba95266bfbc24..c92564a7d41b342e6336dc8474782c7491481a00 100644 --- a/spring-data-mybatis/src/test/resources/infrastructure.xml +++ b/spring-data-mybatis/src/test/resources/infrastructure.xml @@ -10,7 +10,7 @@ - + diff --git a/spring-data-mybatis/src/test/resources/mapper/customer.xml b/spring-data-mybatis/src/test/resources/mapper/customer.xml index d37f1754d8f86a18c597571e61f85ba346533d49..7de010db06860bc277a1c30718de0dad9a9fe166 100644 --- a/spring-data-mybatis/src/test/resources/mapper/customer.xml +++ b/spring-data-mybatis/src/test/resources/mapper/customer.xml @@ -4,11 +4,11 @@ diff --git a/spring-data-mybatis/src/test/resources/mapper/shop.xml b/spring-data-mybatis/src/test/resources/mapper/shop.xml index e1fbc0ec369226f8216653f56e2990692eaa7742..5825b9df834033a1294db1ef7da81fa3058b9b4d 100644 --- a/spring-data-mybatis/src/test/resources/mapper/shop.xml +++ b/spring-data-mybatis/src/test/resources/mapper/shop.xml @@ -3,7 +3,7 @@ "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> - - - - - - - - - - - - - - - - - - - - - - - - - - - -