关联表更新封装
封装 更新 关联
2023-06-13 09:17:27 时间
凭自己的本事和正当手段挣来的钱财,可以使我们赢得道义和幸福——阿基兰
分享一个关联更新函数
package com.ruben.simplestreamquery.util;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.ruben.simplestreamquery.pojo.bo.RelationBO;
import io.github.vampireachao.stream.core.bean.BeanHelper;
import io.github.vampireachao.stream.core.lambda.LambdaExecutable;
import io.github.vampireachao.stream.core.lambda.LambdaHelper;
import io.github.vampireachao.stream.core.lambda.function.SerSupp;
import io.github.vampireachao.stream.core.reflect.ReflectHelper;
import io.github.vampireachao.stream.core.stream.Steam;
import io.github.vampireachao.stream.plugin.mybatisplus.Database;
import io.github.vampireachao.stream.plugin.mybatisplus.Many;
import lombok.val;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import static cn.hutool.core.text.CharSequenceUtil.genSetter;
import static java.util.Collections.emptyList;
/**
* MpUtil
*
* @author VampireAchao
* @since 2023/3/15
*/
public class MpUtil {
public static <T,
K extends Comparable<? super K> & Serializable,
A,
U extends Comparable<? super U> & Serializable,
R> void saveRelation(RelationBO<T, K, A, U, R> bo) {
val mainList = bo.getMainList();
val mainKeys = Steam.of(mainList).map(bo.getMainKey()).toList();
val relationMainGetter = LambdaHelper.resolve(bo.getRelationMain());
val relationMainSetter = getSetter(bo.getRelationMain());
val relationAttachSetter = getSetter(bo.getRelationAttach());
val constructor = ((SerSupp<Constructor<?>>) relationMainGetter.getClazz()::getConstructor).get();
val constructorLambda = LambdaHelper.revert(Supplier.class, constructor);
val nameRelationCompareSetterMap = Steam.of(bo.getRelationCompares())
.map(c -> LambdaHelper.resolve((Serializable) c))
.<String, BiConsumer<R, Object>>toMap(LambdaExecutable::getName, MpUtil::getSetter);
val relationsFromClient = Steam.of(mainList)
.flatMap(vo -> Steam.of(bo.getAttachGetter().apply(vo))
.map(attach -> {
R relation = (R) constructorLambda.get();
relationMainSetter.accept(relation, bo.getMainKey().apply(vo));
relationAttachSetter.accept(relation, bo.getAttachKey().apply(attach));
Steam.of(bo.getAttachCompares()).forEach(c -> {
val executable = LambdaHelper.resolve((Serializable) c);
val setter = nameRelationCompareSetterMap.get(executable.getName());
setter.accept(relation, c.apply(attach));
});
return relation;
})
).toList();
val relationMain = bo.getRelationMain();
val relationsFromDb = Many.of(relationMain).in(mainKeys).query();
if (relationsFromClient.isEmpty()) {
Database.removeByIds(relationsFromDb);
return;
}
if (relationsFromDb.isEmpty()) {
Database.saveFewSql(relationsFromClient);
return;
}
val mainIdRelationsMapFromDb = Steam.of(relationsFromDb)
.group(relationMain);
val mainIdRelationsMapFromClient = Steam.of(relationsFromClient)
.group(relationMain);
mainKeys.forEach(mainKey -> {
val relationListFromDb = mainIdRelationsMapFromDb.getOrDefault(mainKey, emptyList());
val relationListFromClient = mainIdRelationsMapFromClient.getOrDefault(mainKey, emptyList());
if (relationListFromDb.isEmpty() && relationListFromClient.isEmpty()) {
return;
}
if (relationListFromDb.isEmpty()) {
bo.getWillInsertList().addAll(relationListFromClient);
return;
}
if (relationListFromClient.isEmpty()) {
bo.getWillDeleteList().addAll(relationListFromDb);
return;
}
val attachKeyRelationMapFromClient = Steam.of(relationListFromClient)
.toMap(bo.getRelationAttach());
val attachKeysFromClient = attachKeyRelationMapFromClient.keySet();
val attachKeyRelationMapFromDb = Steam.of(relationListFromDb)
.toMap(bo.getRelationAttach());
val attachKeysFromDb = attachKeyRelationMapFromDb.keySet();
// insert
Steam.of(attachKeysFromClient).filter(attachKey -> !attachKeysFromDb.contains(attachKey))
.map(attachKeyRelationMapFromClient::get)
.forEach(bo.getWillInsertList()::add);
// remove
Steam.of(attachKeysFromDb).filter(attachKey -> !attachKeysFromClient.contains(attachKey))
.map(attachKeyRelationMapFromDb::get)
.forEach(bo.getWillDeleteList()::add);
// modify
attachKeysFromDb.retainAll(attachKeysFromClient);
attachKeysFromDb.forEach(attachKey -> {
val relationFromDb = attachKeyRelationMapFromDb.get(attachKey);
val relationFromClient = attachKeyRelationMapFromClient.get(attachKey);
if (Objects.nonNull(relationFromDb) && Objects.nonNull(relationFromClient)) {
Steam.of(bo.getRelationCompares()).forEach(ac -> {
val value = ac.apply(relationFromClient);
if (!Objects.equals(value, ac.apply(relationFromDb))) {
val executable = LambdaHelper.resolve((Serializable) ac);
val setter = nameRelationCompareSetterMap.get(executable.getName());
setter.accept(relationFromDb, value);
if (!bo.getWillUpdateList().contains(relationFromDb)) {
bo.getWillUpdateList().add(relationFromDb);
}
}
});
}
});
});
Database.removeByIds(bo.getWillDeleteList());
Database.saveFewSql(bo.getWillInsertList());
Database.updateFewSql(bo.getWillUpdateList());
}
public static <T, R> SFunction<T, R> getGetter(Class<T> clazz, String property) {
return LambdaHelper.revert(
SFunction.class,
ReflectHelper.getMethod(
clazz,
StrUtil.genGetter(property)
)
);
}
public static <T, R> BiConsumer<T, R> getSetter(SFunction<T, R> getter) {
return getSetter(LambdaHelper.resolve(getter));
}
public static <T, R> BiConsumer<T, R> getSetter(LambdaExecutable executable) {
val setterName = genSetter(BeanHelper.getPropertyName(executable.getName()));
val setter = Steam.of(ReflectHelper.getMethods(executable.getClazz()))
.findFirst(m -> m.getName().equals(setterName))
.orElse(null);
return LambdaHelper.revert(BiConsumer.class, setter);
}
}
用到的bo
package com.ruben.simplestreamquery.pojo.bo;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @author VampireAchao
* @since 2023/3/6 11:32
*/
@Data
public class RelationBO<T,
K extends Comparable<? super K> & Serializable,
A,
U extends Comparable<? super U> & Serializable,
R> {
private List<T> mainList;
private SFunction<T, K> mainKey;
private SFunction<A, U> attachKey;
private SFunction<T, List<A>> attachGetter;
private SFunction<R, K> relationMain;
private SFunction<R, U> relationAttach;
private List<SFunction<A, Object>> attachCompares;
private List<SFunction<R, Object>> relationCompares;
private List<R> willInsertList;
private List<R> willDeleteList;
private List<R> willUpdateList;
public RelationBO() {
attachCompares = new ArrayList<>();
relationCompares = new ArrayList<>();
willInsertList = new ArrayList<>();
willDeleteList = new ArrayList<>();
willUpdateList = new ArrayList<>();
}
}
使用方式:
MpUtil.saveRelation(new RelationBO<RuleParamVO, Integer, PositionVO, String, PositionRule>() {{
setMainList(rules);
setMainKey(RuleParamVO::getId);
setAttachKey(PositionVO::getPositionId);
setAttachGetter(RuleParamVO::getPositions);
setRelationMain(PositionRule::getRuleId);
setRelationAttach(PositionRule::getPositionId);
}});
MpUtil.saveRelation(new RelationBO<RuleParamVO, Integer, SysDepartVO, String, DepartRuleParam>() {{
setMainList(rules);
setMainKey(RuleParamVO::getId);
setAttachKey(SysDepartVO::getDepartId);
setAttachGetter(RuleParamVO::getDepartments);
setRelationMain(DepartRuleParam::getRuleParamId);
setRelationAttach(DepartRuleParam::getDepartmentId);
}});
MpUtil.saveRelation(new RelationBO<RuleParamVO, Integer, PositionVO, String, MemberRule>() {{
setMainList(rules);
setMainKey(RuleParamVO::getId);
setAttachKey(PositionVO::getPositionId);
setAttachGetter(RuleParamVO::getMembers);
setRelationMain(MemberRule::getRuleId);
setRelationAttach(MemberRule::getPositionId);
}});
MpUtil.saveRelation(new RelationBO<RuleParamVO, Integer, StageVO, Integer, RuleStageParam>() {{
setMainList(rules);
setMainKey(RuleParamVO::getId);
setAttachKey(StageVO::getStageId);
setAttachGetter(RuleParamVO::getStages);
setRelationMain(RuleStageParam::getRuleParamId);
setRelationAttach(RuleStageParam::getStageId);
}});