因为数据转换花了几天时间,逻辑上面比较复杂,做下记录,里面还有很大的改进空间。
参考数据格式:
{
"designerId": "63470494272864331",
"dataId": 1,
"transInfo":{
"61532381690609670": 1
},
"modelList": [
"61433580262932491"
],
"dataInfo": {
"61433580262932499": "test-device",
"61532381690609670": 1,
"63470494272864312": "2022-03-17",
"61433580262932491": [
{
"63470494272864320": "气压",
"61532381690609666": "查看操作流程",
"61532381690609668": 11111,
"61532381690609667": "OK",
"id": "Le44NzDPy6"
},
{
"63470494272864320": "温度",
"61532381690609666": "查看操作流程",
"61532381690609668": 2222,
"61532381690609667": "NG",
"id": "97ISPCCqtF"
},
{
"63470494272864320": "湿度",
"61532381690609666": "查看操作流程",
"61532381690609668": 33333,
"61532381690609667": "OK",
"id": "qeY8N-vRre"
},
{
"63470494272864320": "重量",
"61532381690609666": "查看操作流程",
"61532381690609668": 44444,
"61532381690609667": "OK",
"id": "EFDic4byne"
}
]
}
}
情况与处理逻辑:
前端传过来的数据 用的是数据模型ID:值的形式。json格式。直接存储一份json,用于后续返回,这样不用查询的时候从模型抽数据还原格式。
注意存储实体表需要把数据模型转成 key:value形式。
然后按照模型存储到实体表中(模型会生成实体表)
- A模型,一条数据
这种情况最简单。转换成k:v,直接存储就行 - A模型,多条数据list,个别字段前提的情况:
个别字段先转换成k:v。然后循环list,把个别字段依次塞入list中。
待处理问题:如果list在个别字段前面,就存储不到了。需要后置list处理 - A模型,一条数据。B模型多条list,且跟A模型关联
同2情况。先把A模型数据转换k:v,存储数据库。生成ID记录
循环list,塞入ID。或者传入sql语句中也行 - A模型,一条数据。B模型一条数据。
同3情况,转换存储A,转换存储B - A模型,一条数据,但存在多选list。B多条数据
这里需要考虑多选list和数据list的区分。我这里采取形式是前端告知传过来的ID是多选数组,还是对象数据。校验 modelList 即可。或者可以通过instanceof过滤
存储多选的逻辑,这里先没有处理。可以再建立kv表,或者不是特别重要的数据,仅仅展示用,可以数组转字符串。只要能区分开,具体怎么处理都不是大问题了
待验证事项: id:值 和 table@code:值的 探讨
数据量问题。code本身占用空间更大
数据处理。id需要先掉数据库缓存数据,string转long。code需要切分多次
数据维护。code存在修改问题。id存在误删除问题
隐私问题。id不可见,code可见
数组和对象区分问题。id是判断是否存在模型list中。code?
后续扩展上面id可以根据属性做很多特殊处理。判断属性是否是数组,是否是关联其他模型。
目前来看split去切分 table@code的性能损失要大于数据库数据的缓存
数据存储与更新逻辑
前面说了前端把数据传给后台的处理逻辑。这里面有个问题是每次前端保存来的数据,怎么知道是需要新增还是更新。
- 全删全增
实体表里面有个业务ID,每次保存的时候,根据业务ID删除所有数据。然后再新增。这种思路适用于纯业务数据展示用。这样处理最简单 - LIST比对。分出来 addList,updateList,deleteList
依次处理数据。 - 创建一个对照表。记录传进来的数据跟模型的关联关系。
每次更改的是数据跟模型关联关系。不通过实体表存储了
关于数据处理的形式。目前还在探索实验阶段,不做好坏的判断。
核心代码处理逻辑。附加的代码就不贴了。仅做个记录。
/**
* 页面设计器数据存储到数据模型
*/
public void saveModel(DesignerData designerData) {
//根据模型code 获取出来所有的
List<Long> modelIdList = designerData.getModelList();
List<DataModel> modelList = dataModelService.listByModelIdList(modelIdList);
//根据属性id抽取key
Map<Long, DataModel> modelIdMap = modelList.stream()
.collect(Collectors.toMap(
DataModel::getModelId, a -> a
));
//获取模型的所有属性
List<DataModelAttribute> attributeList = attributeService.listByModelIdList(modelIdList);
//根据属性id抽取key
Map<Long, DataModelAttribute> attributeIdMap = attributeList.stream()
.collect(Collectors.toMap(
DataModelAttribute::getAttributeId, a -> a
));
//实际存储模型的map
Map<String, Map<String, Object>> modelDataMap = new HashMap<>();
Map<String, List<Map<String, Object>>> modelDataListMap = new HashMap<>();
//实际存储字段的map
Map<String, Map<String, Object>> modelColumnMap = new HashMap<>();
//字段的数组
Map<String, List<String>> codeListMap = new HashMap<>();
//处理字段
for (Map.Entry<String, Object> entry : designerData.getTransInfo().entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
Long id = Long.valueOf(key);
DataModelAttribute attributeTemp = attributeIdMap.get(id);
String idStr = attributeTemp.getModelId().toString();
codeListMap.computeIfAbsent(idStr, k -> new ArrayList<>());
codeListMap.get(idStr).add(attributeTemp.getCode());
modelColumnMap.computeIfAbsent(idStr, k -> new HashMap<>());
modelColumnMap.get(idStr)
.put(attributeTemp.getCode(), value);
}
//处理数据
for (Map.Entry<String, Object> entry : designerData.getDataInfo().entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
Long id = Long.valueOf(key);
if (modelIdList.contains(id)) {
// 说明这个id是模型,不是字段
//此时obj是一个list
List<Map<String, Object>> objList = (List<Map<String, Object>>) value;
for (Map<String, Object> item : objList) {
Map<String, Map<String, Object>> modelTempMap = new HashMap<>();
for (Map.Entry<String, Object> tempEntry : item.entrySet()) {
String tempIdStr = tempEntry.getKey();
Object tempValue = tempEntry.getValue();
if (tempIdStr.equals("id")) {
continue;
}
Long tempId = Long.valueOf(tempIdStr);
DataModelAttribute attributeTemp = attributeIdMap.get(tempId);
String idStr = attributeTemp.getModelId().toString();
modelTempMap.computeIfAbsent(idStr, k -> new HashMap<>());
modelTempMap.get(idStr)
.put(attributeTemp.getCode(), tempValue);
modelTempMap.get(idStr).putAll(modelDataMap.get(idStr));
}
modelDataListMap.computeIfAbsent(key, k -> new ArrayList<>());
modelDataListMap.get(key)
.add(modelTempMap.get(key));
}
} else {
DataModelAttribute attributeTemp = attributeIdMap.get(id);
String idStr = attributeTemp.getModelId().toString();
modelDataMap.computeIfAbsent(idStr, k -> new HashMap<>());
modelDataMap.get(idStr)
.put(attributeTemp.getCode(), value);
modelDataMap.get(idStr)
.putAll(modelColumnMap.get(idStr));
}
}
for (Map.Entry<String, Map<String, Object>> entry : modelDataMap.entrySet()) {
if (modelDataListMap.get(entry.getKey()) != null) {
//如果列表里面已经有了上面的值,那么在列表中已经合并了
continue;
}
String idStr = entry.getKey();
Long modelId = Long.parseLong(idStr);
//存储对应的model数据
String modelCode = modelIdMap.get(modelId).getCode();
modelDataService.deleteByCode(modelCode, codeListMap.get(idStr), modelColumnMap.get(idStr));
modelDataService.add(modelCode, entry.getValue());
}
for (Map.Entry<String, List<Map<String, Object>>> entry : modelDataListMap.entrySet()) {
String idStr = entry.getKey();
Long modelId = Long.parseLong(idStr);
String modelCode = modelIdMap.get(modelId).getCode();
modelDataService.deleteByCode(modelCode, codeListMap.get(idStr), modelColumnMap.get(idStr));
//存储对应的model数据
entry.getValue().forEach(item -> {
modelDataService.add(modelCode, item);
});
}
}