关联更新封装(二)

简介: 关联更新封装(二)

仁者爱人,有礼者敬人。爱人者,人恒爱之;敬人者,人恒敬之。——孟子

前两天写了关联表更新封装

今天写个另一种类型的

public static <T,
        K extends Comparable<? super K> & Serializable,
        A,
        L extends Comparable<? super L> & Serializable>
BaseDbBO<A> saveAttach(AttachBO<T, K, A> bo) {
    val mainList = bo.getMainList();
    val mainKeys = Steam.of(mainList).map(bo.getMainKey()).toList();
    val attachKeyExecutable = LambdaHelper.resolve(bo.getAttachKey());
    val attachKeySetter = getSetter(attachKeyExecutable);
    val compareGetterSetterMap = Steam.of(bo.getAttachCompares())
            .toMap(Function.identity(), MpUtil::getSetter);
    val attachListFromClient = Steam.of(mainList).flat(m -> Steam.of(bo.getAttachGetter().apply(m))
                    .peek(a -> attachKeySetter.accept(a, bo.getMainKey().apply(m))))
            .toList();
    val attachGetterExecutable = LambdaHelper.resolve(bo.getAttachGetter());
    val field = ReflectHelper.getField(attachGetterExecutable.getClazz(), BeanHelper.getPropertyName(attachGetterExecutable.getName()));
    Class<A> genericType = (Class<A>) ReflectHelper.getGenericTypes(field.getGenericType())[0];
    val attachListFromDb = Many.of(bo.getAttachKey()).in(mainKeys)
            .value(v -> {
                val vo = ((SerSupp<A>) genericType::newInstance).get();
                BeanUtils.copyProperties(v, vo);
                return vo;
            })
            .query();
    val attachTableInfo = TableInfoHelper.getTableInfo(attachKeyExecutable.getClazz());
    val attachPrimaryKey = MpUtil.<A, L>getGetter((Class<A>) attachKeyExecutable.getClazz(),
            attachTableInfo.getKeyProperty());
    val attachKeyListFromDb = Steam.of(attachListFromDb).map(attachPrimaryKey).toList();
    if (attachKeyListFromDb.isEmpty()) {
        bo.setWillInsertList(attachListFromClient);
        bo.setDataList(attachListFromClient);
        return bo;
    }
    if (attachListFromClient.isEmpty()) {
        bo.setWillDeleteList(attachListFromDb);
        return bo;
    }
    val mainIdAttachesMapFromDb = Steam.of(attachListFromDb).group(bo.getAttachKey());
    val mainIdAttachesMapFromClient = Steam.of(attachListFromClient).group(bo.getAttachKey());
    mainKeys.forEach(mainKey -> {
        val attachesFromDb = mainIdAttachesMapFromDb.getOrDefault(mainKey, emptyList());
        val attachesFromClient = mainIdAttachesMapFromClient.getOrDefault(mainKey, emptyList());
        if (attachesFromDb.isEmpty() && attachesFromClient.isEmpty()) {
            return;
        }
        if (attachesFromDb.isEmpty()) {
            bo.getWillInsertList().addAll(attachesFromClient);
            return;
        }
        if (attachesFromClient.isEmpty()) {
            bo.getWillDeleteList().addAll(attachesFromDb);
            return;
        }
        val idAttachMapFromDb = Steam.of(attachesFromDb).toMap(attachPrimaryKey);
        // insert
        Steam.of(attachesFromClient)
                .filter(attach -> {
                    val id = attachPrimaryKey.apply(attach);
                    return Objects.isNull(id) || !idAttachMapFromDb.containsKey(id);
                })
                .forEach(bo.getWillInsertList()::add);
        val idAttachMapFromClient = Steam.of(attachesFromClient)
                .filter(attach -> {
                    val id = attachPrimaryKey.apply(attach);
                    return Objects.nonNull(id);
                }).toMap(attachPrimaryKey);
        // remove
        val attachKeysFromDb = idAttachMapFromDb.keySet();
        Steam.of(attachKeysFromDb)
                .filter(id -> !idAttachMapFromClient.containsKey(id))
                .map(idAttachMapFromDb::get)
                .forEach(bo.getWillDeleteList()::add);
        // modify
        attachKeysFromDb.retainAll(idAttachMapFromClient.keySet());
        attachKeysFromDb.forEach(attachKey -> {
            val attachFromDb = idAttachMapFromDb.get(attachKey);
            val attachFromClient = idAttachMapFromClient.get(attachKey);
            if (Objects.nonNull(attachFromDb) && Objects.nonNull(attachFromClient)) {
                Steam.of(bo.getAttachCompares()).forEach(ac -> {
                    val value = ac.apply(attachFromClient);
                    if (!Objects.equals(value, ac.apply(attachFromDb))) {
                        val executable = LambdaHelper.resolve((Serializable) ac);
                        val setter = compareGetterSetterMap.get(ac);
                        val fieldType = ReflectHelper.getField(executable.getClazz(),
                                BeanHelper.getPropertyName(executable.getName())).getType();
                        setter.accept(attachFromDb, value);
                        if (isComparable(fieldType) && (!bo.getWillUpdateList().contains(attachFromDb))) {
                            bo.getWillUpdateList().add(attachFromDb);
                        }
                    }
                });
            }
        });
    });
    bo.setAfterExecuted(b -> {
        attachListFromDb.removeIf(bo.getWillDeleteList()::contains);
        attachListFromDb.addAll(bo.getWillInsertList());
        val idAttachMap = Steam.of(attachListFromDb).toMap(attachPrimaryKey);
        attachListFromClient.forEach(data -> {
            val primaryKey = attachPrimaryKey.apply(data);
            idAttachMap.put(primaryKey, data);
        });
        bo.setDataList(new ArrayList<>(idAttachMap.values()));
    });
    return bo;
}


使用起来也差不多

val cards = MpUtil.saveAttach(new AttachBO<ProductDetailVO, Long, ProductDetailCardVO>() {{
    setMainList(vos);
    setMainKey(ProductDetailVO::getId);
    setAttachKey(ProductDetailCardVO::getDetailId);
    setAttachGetter(ProductDetailVO::getCardList);
    setAttachCompares(Lists.of(
            ProductDetailCardVO::getType,
            ProductDetailCardVO::getCanAdd,
            ProductDetailCardVO::getViewMode,
            ProductDetailCardVO::getDataList
    ));
}}).execute();
相关文章
|
2月前
|
缓存 架构师 NoSQL
五种更新缓存的组合方式
【4月更文挑战第19天】更新缓存的步骤特别简单,共两步:更新数据库和更新缓存。但这简单的两步中需要考虑很多问题。
|
2月前
|
C++
57静态关联与动态关联
57静态关联与动态关联
23 0
|
7月前
关联更新封装(三)
关联更新封装(三)
38 2
|
7月前
关联表更新封装
关联表更新封装
31 2
|
2月前
activiti并行网关执行时每个关联表的变化
activiti并行网关执行时每个关联表的变化
98 0
|
12月前
|
Java uml
依赖和关联的对比和区别
依赖和关联的对比和区别
140 0
|
敏捷开发 前端开发 Ruby
RailsAdmin如何实现自定义操作
RailsAdmin如何实现自定义操作
71 0
|
存储 编译器 程序员
C++数据定义及相关操作
C++数据定义及相关操作
115 0
C++数据定义及相关操作
系统通信方式操作
系统通信方式操作
51 0
系统通信方式操作
流程定义查询和删除
流程定义查询流程定义查询和删除