feat: 增加关联信息

This commit is contained in:
wangyu 2024-06-27 18:03:05 +08:00
parent 873635d6a9
commit 0f27376a5f
16 changed files with 341 additions and 51 deletions

View File

@ -6,6 +6,7 @@ import com.flyfish.framework.query.Query;
import com.flyfish.framework.query.QueryDefinition; import com.flyfish.framework.query.QueryDefinition;
import com.flyfish.framework.utils.CopyUtils; import com.flyfish.framework.utils.CopyUtils;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -35,6 +36,7 @@ public class BaseQo<T extends Domain> implements Qo<T> {
protected List<String> fields; protected List<String> fields;
@Getter @Getter
@Setter
protected boolean fetchRef; protected boolean fetchRef;
public Qo<T> accept(List<T> result, Pageable pageable) { public Qo<T> accept(List<T> result, Pageable pageable) {

View File

@ -0,0 +1,32 @@
package com.flyfish.framework.annotations.relation;
import org.springframework.data.annotation.Reference;
import org.springframework.data.annotation.Transient;
import java.lang.annotation.*;
/**
* 数据库关联信息
*
* @author wangyu
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Transient
@Reference
public @interface Association {
/**
* @return 关联在本对象上的字段名称
* 如当前表的detail_id字段对应detail表的id字段则该值为 detail_id
*/
String field() default "";
/**
* @return 关联在外部对象上的字段名称注意禁止循环依赖
* 如当前表不存在目标表detail的关联id目标表关联本实体的id为main_id则该值为main_id
* 与field互斥同时指定永远都以field为主
*/
String foreignField() default "";
}

View File

@ -16,6 +16,11 @@ import java.util.Optional;
*/ */
public interface Qo<T> { public interface Qo<T> {
/**
* 查询键
*/
String KEY = "query";
/** /**
* 获取分页对象 * 获取分页对象
* *

View File

@ -2,6 +2,8 @@ package com.flyfish.framework.r2dbc.config;
import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.r2dbc.config.callback.ReferenceR2dbcCallback; import com.flyfish.framework.r2dbc.config.callback.ReferenceR2dbcCallback;
import com.flyfish.framework.r2dbc.metadata.R2dbcMetadataManager;
import com.flyfish.framework.r2dbc.metadata.impl.SimpleR2dbcMetadataManager;
import com.flyfish.framework.r2dbc.operations.R2dbcReactiveEntityOperations; import com.flyfish.framework.r2dbc.operations.R2dbcReactiveEntityOperations;
import com.flyfish.framework.r2dbc.repository.factory.DefaultReactiveRepositoryFactoryBean; import com.flyfish.framework.r2dbc.repository.factory.DefaultReactiveRepositoryFactoryBean;
import com.flyfish.framework.r2dbc.repository.impl.DefaultReactiveRepositoryImpl; import com.flyfish.framework.r2dbc.repository.impl.DefaultReactiveRepositoryImpl;
@ -42,8 +44,13 @@ public class R2dbcDataConfig {
} }
@Bean @Bean
public EntityCallback<Domain> referenceR2dbcCallback() { public EntityCallback<Domain> referenceR2dbcCallback(R2dbcMetadataManager metadataManager) {
return new ReferenceR2dbcCallback(); return new ReferenceR2dbcCallback(metadataManager);
}
@Bean
public R2dbcMetadataManager r2dbcMetadataManager() {
return new SimpleR2dbcMetadataManager();
} }
/** /**

View File

@ -1,32 +1,66 @@
package com.flyfish.framework.r2dbc.config.callback; package com.flyfish.framework.r2dbc.config.callback;
import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Domain;
import lombok.Setter; import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.r2dbc.metadata.R2dbcMetadataManager;
import com.flyfish.framework.r2dbc.metadata.R2dbcTableMetadata;
import com.flyfish.framework.repository.DefaultReactiveRepository;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.r2dbc.core.R2dbcEntityOperations;
import org.springframework.data.r2dbc.mapping.event.AfterConvertCallback; import org.springframework.data.r2dbc.mapping.event.AfterConvertCallback;
import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.util.Lazy;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
public class ReferenceR2dbcCallback implements AfterConvertCallback<Domain>, ApplicationContextAware { import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
@Setter @RequiredArgsConstructor
private ApplicationContext applicationContext; public class ReferenceR2dbcCallback implements AfterConvertCallback<Domain> {
@Setter(onMethod_ = @Autowired) private final R2dbcMetadataManager r2dbcMetadataManager;
private ObjectProvider<R2dbcEntityOperations> entityOperations; private Lazy<Map<Class<?>, DefaultReactiveRepository<?>>> repositories;
@Override @Override
@NonNull @NonNull
public Publisher<Domain> onAfterConvert(@NonNull Domain entity, @NonNull SqlIdentifier table) { public Publisher<Domain> onAfterConvert(@NonNull Domain entity, @NonNull SqlIdentifier table) {
return Mono.deferContextual(ctx -> {
Optional<Qo<? extends Domain>> query = ctx.getOrEmpty(Qo.KEY);
query.ifPresent(qo -> entity.setCurrentUser(qo.getUser()));
// 判断是否需要获取关联信息
boolean fetchRefs = query.map(Qo::isFetchRef).orElse(false);
if (fetchRefs) {
return doFetch(entity);
}
return Mono.just(entity);
});
}
/**
* 完成填充
*
* @param entity 实体
* @return 结果
*/
private Mono<Domain> doFetch(Domain entity) {
// 遍历fields找到要注入的数据 // 遍历fields找到要注入的数据
entityOperations.getIfAvailable(); R2dbcTableMetadata metadata = r2dbcMetadataManager.getMetadata(entity.getClass());
// 尝试填充关联
if (CollectionUtils.isNotEmpty(metadata.getAssociations())) {
}
return Mono.just(entity); return Mono.just(entity);
} }
@Autowired
public void setRepositories(ObjectProvider<DefaultReactiveRepository<?>> repositories) {
this.repositories = Lazy.of(() -> repositories.stream()
.collect(Collectors.toMap(repo -> repo.getEntityInformation().getJavaType(), Function.identity())));
}
} }

View File

@ -0,0 +1,19 @@
package com.flyfish.framework.r2dbc.metadata;
import com.flyfish.framework.domain.base.Domain;
/**
* r2dbc元数据管理器
*
* @author wangyu
*/
public interface R2dbcMetadataManager {
/**
* 获取元数据
*
* @param entityClass 实体类名
* @return 结果
*/
R2dbcTableMetadata getMetadata(Class<? extends Domain> entityClass);
}

View File

@ -0,0 +1,41 @@
package com.flyfish.framework.r2dbc.metadata;
import com.flyfish.framework.annotations.Property;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.r2dbc.metadata.reference.R2dbcAssociation;
import com.flyfish.framework.r2dbc.metadata.reference.R2dbcCollection;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 表元数据
*
* @author wangyu
*/
@Data
@Property("表的元数据,用于关联查询")
public class R2dbcTableMetadata {
@Property("表名")
private String tableName;
@Property("表实体类名")
private Class<? extends Domain> entityClass;
@Property("一对一关联信息")
private List<R2dbcAssociation> associations = new ArrayList<>();
@Property("一对多关联信息")
private List<R2dbcCollection> collections = new ArrayList<>();
public R2dbcTableMetadata(Class<? extends Domain> entityClass) {
this.entityClass = entityClass;
}
public void addAssociation(String field, boolean inner) {
this.associations.add(R2dbcAssociation.of(entityClass, field, inner));
}
}

View File

@ -0,0 +1,106 @@
package com.flyfish.framework.r2dbc.metadata.impl;
import com.flyfish.framework.annotations.relation.Association;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.r2dbc.metadata.R2dbcMetadataManager;
import com.flyfish.framework.r2dbc.metadata.R2dbcTableMetadata;
import com.flyfish.framework.r2dbc.metadata.reference.R2dbcAssociation;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.lang.NonNull;
import org.springframework.util.ReflectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 简单的元数据管理器
*
* @author wangyu
* 基于线程安全的反射方法进行加载并持有
*/
public class SimpleR2dbcMetadataManager implements R2dbcMetadataManager {
private final ConcurrentMap<Class<? extends Domain>, R2dbcTableMetadata> METADATA_STORE = new ConcurrentHashMap<>();
/**
* 获取元数据
*
* @param entityClass 实体类名
* @return 结果
*/
@Override
public R2dbcTableMetadata getMetadata(Class<? extends Domain> entityClass) {
return METADATA_STORE.computeIfAbsent(entityClass, this::computeMetadata);
}
/**
* 计算元数据信息
*
* @param entityClass 实体类
* @return 结果
*/
private R2dbcTableMetadata computeMetadata(Class<? extends Domain> entityClass) {
MetadataCreator creator = new MetadataCreator(entityClass);
ReflectionUtils.doWithFields(entityClass, creator);
return creator.metadata;
}
private static class MetadataCreator implements ReflectionUtils.FieldCallback {
private final Map<String, PropertyDescriptor> descriptors;
private final ClassTypeInformation<? extends Domain> typeInformation;
private final R2dbcTableMetadata metadata;
private MetadataCreator(Class<? extends Domain> entityClass) {
this.descriptors = Arrays.stream(BeanUtils.getPropertyDescriptors(entityClass))
.collect(Collectors.toMap(PropertyDescriptor::getName, Function.identity()));
this.typeInformation = ClassTypeInformation.from(entityClass);
this.metadata = new R2dbcTableMetadata(entityClass);
}
/**
* Perform an operation using the given field.
*
* @param field the field to operate on
*/
@Override
public void doWith(@NonNull Field field) throws IllegalArgumentException, IllegalAccessException {
Property property = Property.of(typeInformation, field, descriptors.get(field.getName()));
Class<?> fieldType = property.getType();
ReflectionUtils.makeAccessible(field);
Association association = AnnotatedElementUtils.findMergedAnnotation(field, Association.class);
if (null != association) {
if (ClassUtils.isAssignable(fieldType, Domain.class)) {
// 一对一关联
if (StringUtils.isNotBlank(association.field())) {
metadata.addAssociation(association.field(), true);
} else if (StringUtils.isNotBlank(association.foreignField())) {
metadata.addAssociation(association.foreignField(), false);
} else {
// 尚且不支持空白策略
}
} else if (ClassUtils.isAssignable(fieldType, Collection.class)) {
// 一对多关联
}
}
}
}
}

View File

@ -0,0 +1,25 @@
package com.flyfish.framework.r2dbc.metadata.reference;
import com.flyfish.framework.annotations.Property;
import com.flyfish.framework.domain.base.Domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@Property("一对一关联查询")
@AllArgsConstructor
public class R2dbcAssociation {
@Property("关联实体类")
private Class<? extends Domain> entityClass;
@Property("关联字段")
private String field;
@Property("字段是否在当前实体内部")
boolean inner;
public static R2dbcAssociation of(Class<? extends Domain> entityClass, String field, boolean inner) {
return new R2dbcAssociation(entityClass, field, inner);
}
}

View File

@ -0,0 +1,16 @@
package com.flyfish.framework.r2dbc.metadata.reference;
import com.flyfish.framework.annotations.Property;
import com.flyfish.framework.domain.base.Domain;
import lombok.Data;
@Data
@Property("一对多关联查询")
public class R2dbcCollection {
@Property("关联实体类")
private Class<? extends Domain> entityClass;
@Property("关联字段")
private String field;
}

View File

@ -18,7 +18,6 @@ import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query; import org.springframework.data.relational.core.query.Query;
import org.springframework.data.relational.repository.query.RelationalEntityInformation; import org.springframework.data.relational.repository.query.RelationalEntityInformation;
import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.util.CastUtils;
import org.springframework.data.util.Lazy; import org.springframework.data.util.Lazy;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -59,12 +58,6 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
.getRequiredPersistentEntity(entity.getJavaType())); .getRequiredPersistentEntity(entity.getJavaType()));
} }
@Override
@NonNull
public Mono<T> findById(@NonNull String id) {
return super.findById(id).flatMap(this::afterSelect);
}
/** /**
* 通过名称查找一个 * 通过名称查找一个
* *
@ -75,8 +68,7 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
public Mono<T> findByName(String name) { public Mono<T> findByName(String name) {
if (StringUtils.isNotBlank(name)) { if (StringUtils.isNotBlank(name)) {
return entityOperations return entityOperations
.selectOne(Query.query(Criteria.where("name").is(name)), entity.getJavaType()) .selectOne(Query.query(Criteria.where("name").is(name)), entity.getJavaType());
.flatMap(this::afterSelect);
} }
return Mono.empty(); return Mono.empty();
} }
@ -93,7 +85,7 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
public Mono<T> findOne(Qo<T> query) { public Mono<T> findOne(Qo<T> query) {
return getQuery(query) return getQuery(query)
.flatMap(querying -> entityOperations.selectOne(querying, entity.getJavaType())) .flatMap(querying -> entityOperations.selectOne(querying, entity.getJavaType()))
.flatMap(t -> this.afterSelect(query, t)); .contextWrite(ctx -> ctx.put(Qo.KEY, query));
} }
/** /**
@ -106,8 +98,8 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
@Override @Override
public Flux<T> findAll(Qo<T> query) { public Flux<T> findAll(Qo<T> query) {
return getQuery(query) return getQuery(query)
.flatMapMany(querying -> entityOperations.select(querying, entity.getJavaType()) .flatMapMany(querying -> entityOperations.select(querying, entity.getJavaType()))
.flatMap(t -> this.afterSelect(query, t))); .contextWrite(ctx -> ctx.put(Qo.KEY, query));
} }
/** /**
@ -123,8 +115,8 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
@Override @Override
public Flux<T> findAll(Qo<T> query, Sort sort) { public Flux<T> findAll(Qo<T> query, Sort sort) {
return getQuery(query) return getQuery(query)
.flatMapMany(querying -> entityOperations.select(querying.sort(sort), entity.getJavaType()) .flatMapMany(querying -> entityOperations.select(querying.sort(sort), entity.getJavaType()))
.flatMap(t -> this.afterSelect(query, t))); .contextWrite(ctx -> ctx.put(Qo.KEY, query));
} }
/** /**
@ -140,10 +132,10 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
return getQuery(query) return getQuery(query)
.flatMap(querying -> entityOperations.select(querying.with(pageable), .flatMap(querying -> entityOperations.select(querying.with(pageable),
entity.getJavaType()) entity.getJavaType())
.flatMap(t -> this.afterSelect(query, t))
.collectList() .collectList()
.flatMap(list -> ReactivePageableExecutionUtils.getPage(list, pageable, this.count(query)))) .flatMap(list -> ReactivePageableExecutionUtils.getPage(list, pageable, this.count(query))))
.defaultIfEmpty(Page.empty()); .defaultIfEmpty(Page.empty())
.contextWrite(ctx -> ctx.put(Qo.KEY, query));
} }
/** /**
@ -170,7 +162,7 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
public Flux<T> findAllByValues(String key, List<?> values) { public Flux<T> findAllByValues(String key, List<?> values) {
Criteria criteria = Criteria.where(key).in(values); Criteria criteria = Criteria.where(key).in(values);
Query query = Query.query(criteria); Query query = Query.query(criteria);
return entityOperations.select(query, entity.getJavaType()).flatMap(this::afterSelect); return entityOperations.select(query, entity.getJavaType());
} }
/** /**
@ -247,13 +239,4 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleR2dbc
private Mono<Query> getQuery(Qo<T> qo) { private Mono<Query> getQuery(Qo<T> qo) {
return Mono.justOrEmpty(qo.getQuery(entity)); return Mono.justOrEmpty(qo.getQuery(entity));
} }
private Mono<T> afterSelect(T entity) {
return Mono.just(entity);
}
private Mono<T> afterSelect(Qo<T> qo, T entity) {
entity.setCurrentUser(qo.getUser());
return afterSelect(entity);
}
} }

View File

@ -4,7 +4,6 @@ import com.flyfish.framework.r2dbc.config.R2dbcDataConfig;
import com.flyfish.framework.r2dbc.repository.TestDO; import com.flyfish.framework.r2dbc.repository.TestDO;
import com.flyfish.framework.r2dbc.repository.TestQO; import com.flyfish.framework.r2dbc.repository.TestQO;
import com.flyfish.framework.r2dbc.repository.TestRepository; import com.flyfish.framework.r2dbc.repository.TestRepository;
import com.flyfish.framework.r2dbc.repository.reference.TestAsso;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -26,9 +25,12 @@ public class R2DbcRepositoryTest {
@Test @Test
public void test() { public void test() {
TestQO qo = new TestQO(); TestQO qo = new TestQO();
qo.setName(""); qo.setName("2");
// 开启关联查询
qo.setFetchRef(true);
TestDO test = new TestDO(); TestDO test = new TestDO();
test.setId("1"); test.setId("100");
test.setCode("ttt"); test.setCode("ttt");
test.setName("测试名称"); test.setName("测试名称");
test.setOtherId("1"); test.setOtherId("1");

View File

@ -1,11 +1,10 @@
package com.flyfish.framework.r2dbc.repository; package com.flyfish.framework.r2dbc.repository;
import com.flyfish.framework.annotations.relation.Association;
import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.AuditDomain;
import com.flyfish.framework.r2dbc.repository.reference.TestAsso; import com.flyfish.framework.r2dbc.repository.reference.TestAsso;
import com.flyfish.framework.r2dbc.repository.reference.TestChild; import com.flyfish.framework.r2dbc.repository.reference.TestChild;
import lombok.Data; import lombok.Data;
import org.springframework.data.annotation.Reference;
import org.springframework.data.annotation.Transient;
import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.relational.core.mapping.Table;
@ -16,10 +15,11 @@ import java.util.List;
public class TestDO extends AuditDomain { public class TestDO extends AuditDomain {
@Column("other_id") @Column("other_id")
@Reference
private String otherId; private String otherId;
@Reference(TestChild.class) @Association(field = "other_id")
@Transient private TestAsso asso;
@Association(foreignField = "parent_id")
private List<TestChild> children; private List<TestChild> children;
} }

View File

@ -1,5 +1,5 @@
spring: spring:
r2dbc: r2dbc:
url: r2dbc:mysql://127.0.0.1:3306/test?allowMultiQueries=true&useUnicode=true&ssl=false&characterEncoding=UTF-8&serverZoneId=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true url: r2dbc:mysql://127.0.0.1:3306/test?allowMultiQueries=true&useUnicode=true&ssl=true&characterEncoding=UTF-8&serverZoneId=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true
username: root username: root
password: Unicom#2018 password: Unicom#2018

View File

@ -1,2 +1,3 @@
DROP TABLE IF EXISTS `test`; DROP TABLE IF EXISTS `test`;
DROP TABLE IF EXISTS `test_child`; DROP TABLE IF EXISTS `test_child`;
DROP TABLE IF EXISTS `test_asso`;

View File

@ -14,6 +14,10 @@ CREATE TABLE IF NOT EXISTS `test`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) COMMENT '测试表'; ) COMMENT '测试表';
REPLACE INTO `test`
VALUES ('1', '1', '测试1', '1', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false),
('2', '2', '测试2', '2', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false);
CREATE TABLE IF NOT EXISTS `test_child` CREATE TABLE IF NOT EXISTS `test_child`
( (
`id` VARCHAR(36) NOT NULL COMMENT '主键', `id` VARCHAR(36) NOT NULL COMMENT '主键',
@ -30,6 +34,14 @@ CREATE TABLE IF NOT EXISTS `test_child`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) COMMENT '测试子表'; ) COMMENT '测试子表';
REPLACE INTO `test_child`
VALUES ('1', '1', '子表1', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false),
('2', '2', '子表2', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false),
('3', '3', '子表3', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false),
('4', '4', '子表4', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false),
('5', '5', '子表5', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false);
CREATE TABLE IF NOT EXISTS `test_asso` CREATE TABLE IF NOT EXISTS `test_asso`
( (
`id` VARCHAR(36) NOT NULL COMMENT '主键', `id` VARCHAR(36) NOT NULL COMMENT '主键',
@ -44,3 +56,8 @@ CREATE TABLE IF NOT EXISTS `test_asso`
`delete` BIT(1) NOT NULL DEFAULT b'0', `delete` BIT(1) NOT NULL DEFAULT b'0',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) COMMENT '测试关联表'; ) COMMENT '测试关联表';
REPLACE INTO `test_asso`
VALUES ('1', '1', 'baba ', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false),
('2', '1', 'mama ', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, null, null, null, null, false);