zl程序教程

您现在的位置是:首页 >  前端

当前栏目

关联表更新封装

封装 更新 关联
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);
}});