凭自己的本事和正当手段挣来的钱财,可以使我们赢得道义和幸福——阿基兰
分享一个关联更新函数
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> BaseDbBO<R> 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 relationClass = (Class<?>) relationMainGetter.getInstantiatedTypes()[0]; val constructor = ((SerSupp<Constructor<?>>) relationClass::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 willInsertList = Steam.of(mainList).flatMap(vo -> Steam.of(bo.getAttachGetter().apply(vo))) .filter(bo.getAttachKey(), null) .toList(); if (!willInsertList.isEmpty()) { if (bo.getInsertOnMissAttach()) { Database.saveFewSql(willInsertList); } else { throw new IllegalStateException("attach data missing"); } } 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()) { bo.setWillDeleteList(relationsFromDb); return bo; } if (relationsFromDb.isEmpty()) { bo.setWillInsertList(relationsFromClient); bo.setDataList(relationsFromClient); return bo; } 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); } } }); } }); }); bo.setAfterExecuted(b -> { val relationPrimaryKey = MpUtil.getGetter((Class<R>) relationClass, TableInfoHelper.getTableInfo(relationClass).getKeyProperty()); relationsFromDb.removeIf(bo.getWillDeleteList()::contains); relationsFromDb.addAll(bo.getWillInsertList()); val idAttachMap = Steam.of(relationsFromDb).toMap(relationPrimaryKey); relationsFromClient.forEach(data -> { val pk = relationPrimaryKey.apply(data); idAttachMap.put(pk, data); }); bo.setDataList(new ArrayList<>(idAttachMap.values())); }); return bo; } 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
import io.github.vampireachao.stream.core.lambda.function.SerCons; import io.github.vampireachao.stream.plugin.mybatisplus.Database; import lombok.Data; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * @author VampireAchao * @since 2023/3/16 11:07 */ @Data public abstract class BaseDbBO<T> { private List<T> willInsertList; private List<T> willDeleteList; private List<T> willUpdateList; private List<T> dataList; private Consumer<BaseDbBO<T>> afterExecuted; public BaseDbBO() { dataList = new ArrayList<>(); willInsertList = new ArrayList<>(); willDeleteList = new ArrayList<>(); willUpdateList = new ArrayList<>(); afterExecuted = SerCons.nothing(); } public List<T> execute() { Database.removeByIds(getWillDeleteList()); Database.saveFewSql(getWillInsertList()); Database.updateFewSql(getWillUpdateList()); afterExecuted.accept(this); return dataList; } public BaseDbBO<T> add(BaseDbBO<T> bo) { this.getWillInsertList().addAll(bo.getWillInsertList()); this.getWillDeleteList().addAll(bo.getWillDeleteList()); this.getWillUpdateList().addAll(bo.getWillUpdateList()); this.afterExecuted = SerCons.multi(this.afterExecuted::accept, bo.getAfterExecuted()::accept); return this; } }
使用方式:
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); }}).execute(); 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); }});
import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author VampireAchao * @since 2023/3/6 11:32 */ @Data @EqualsAndHashCode(callSuper = true) public class RelationBO<T, K extends Comparable<? super K> & Serializable, A, U extends Comparable<? super U> & Serializable, R> extends BaseDbBO<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 Boolean insertOnMissAttach; public RelationBO() { super(); attachCompares = new ArrayList<>(); relationCompares = new ArrayList<>(); insertOnMissAttach = false; } }
相关解释如下: