金蝶ERP获取元数据的字段属性、表名、库名


前言

在我们使用金蝶云苍穹进行实际开发的时候,会遇到在后端获取前端页面各个属性的时候,例如:字段标识、字段名、字段类型、字段长度等。


一、页面模型获取

  1. 采用缓存获取页面模型:
    MainEntityType entityType = EntityMetadataCache.getDataEntityType(entityName);
  2. 采用工具类获取页面模型:
    MainEntityType mainEntityType = MetadataServiceHelper.getDataEntityType(entityName);

二、使用步骤

1.采用缓存获取

代码如下(示例):

package rea5.cosmic.debug.bamp.mservicehelper.mservice;

import cfca.org.slf4j.Logger;
import cfca.org.slf4j.LoggerFactory;
import kd.bos.algo.DataSet;
import kd.bos.algo.Row;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.dataentity.metadata.dynamicobject.DynamicPropertyCollection;
import kd.bos.db.DB;
import kd.bos.db.DBRoute;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.EntityType;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.property.TextProp;
import kd.bos.servicehelper.MetadataServiceHelper;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CheckDBServiceHelper {
    private static final Logger logger = LoggerFactory.getLogger(CheckDBServiceHelper.class);

    public Map<String, Map<String, Object>> checkDB(String entityName) {
        Map<String, Map<String, Object>> result = new HashMap<>();
        try {
            //MainEntityType mainEntityType = EntityMetadataCache.getDataEntityType(entityName);
            //返回结果
            Map<String, EntityType> allEntities = mainEntityType.getAllEntities();//单据或者基础资料的所有表信息(包含单据体)
            for (Map.Entry<String, EntityType> allEntitiesInformation : allEntities.entrySet()) {
                Map<String, Object> fieldMap = new HashMap<>();
                String dbKeyRoute = "";//数据库路由
                String tableName = "";//表名
                String entryName = "";//实体标识
                DynamicPropertyCollection fields = null;//属性
                EntityType tableInformation = allEntitiesInformation.getValue();//单个表的信息
                // 获取 DynamicObjectType 类的所有字段
                Field[] dynamicObjectTypeFields = DynamicObjectType.class.getDeclaredFields();
                Field[] entityTypeFields = EntityType.class.getDeclaredFields();
                // 合并数组
                Field[] combinedFields = Stream.concat(Arrays.stream(dynamicObjectTypeFields), Arrays.stream(entityTypeFields))
                        .toArray(Field[]::new);
                for (Field field : combinedFields) {
                    field.setAccessible(true); // 设置字段可访问
                    try {
                        Object value = field.get(tableInformation);
                        String name = field.getName();
                        switch (name) {
                            case "dbRouteKey":
                                // 代码块
                                dbKeyRoute = value.toString();
                                break;
                            case "_tableName":
                                // 代码块
                                tableName = value.toString();
                                break;
                            case "_name":
                                // 代码块
                                entryName = value.toString();
                                break;
                            case "_properties":
                                // 代码块
                                if (value instanceof List) {
                                    @SuppressWarnings("unchecked")
                                    DynamicPropertyCollection castedFields = (DynamicPropertyCollection) value;
                                    fields = castedFields;
                                }
                                break;
                            default:
                                // 默认代码块
                                break;
                        }
                    } catch (IllegalAccessException ex) {
                        logger.error("KN_无法访问字段: {}", ex.getMessage(), ex);
                    }
                }
                //执行SQL
                if (!tableName.isEmpty()) {
                    String sql = "SELECT data_type,table_schema,table_name,column_name,character_maximum_length FROM information_schema.columns " +
                            "WHERE table_schema = 'public'AND data_type IN ('character varying', 'character') and table_name = ?";
                    DataSet rows = DB.queryDataSet(this.getClass().toString(), DBRoute.of(dbKeyRoute), sql, new String[]{tableName.toLowerCase()});
                    //数据库字段和长度的map集合
                    Map<String, Integer> DBFieldAndLength = new HashMap<>();
                    for (Row row : rows) {
                        DBFieldAndLength.put(row.getString("column_name"), row.getInteger("character_maximum_length"));
                    }
                    //实体标识和长度的map集合
                    Map<String, Integer> localFieldAndLength = new HashMap<>();
                    assert fields != null;
                    fields.forEach(item -> {
                        String alias = item.getAlias();
                        if (StringUtils.hasText(alias) && item instanceof TextProp) {
                            localFieldAndLength.put(alias, ((TextProp) item).getMaxLenth());
                        }
                    });
                    //有问题的字段集合
                    Map<String, Integer> problemFields = new HashMap<>();
                    //对比字段
                    localFieldAndLength.forEach((itemKey, itemValue) -> {
                        Integer DBValueData = DBFieldAndLength.get(itemKey);
                        if (DBValueData != null && DBValueData.compareTo(itemValue) != 0) {
                            problemFields.put(itemKey, itemValue);
                        }
                    });
                    //生成扩容sql
                    if (!problemFields.isEmpty()) {
                        StringBuilder expSql = new StringBuilder("ALTER TABLE ");
                        expSql.append(tableName);
                        //字段个数
                        List<String> sqlList = problemFields.keySet().stream()
                                .map(item -> " ALTER COLUMN " + item + " TYPE character varying(" + problemFields.get(item) + ")")
                                .collect(Collectors.toList());
                        expSql.append(String.join(",", sqlList));
                        doRes(fieldMap, expSql.toString(), String.format("存在以下字段:%s 实体与数据库长度不一致。", String.join(",", problemFields.keySet())), localFieldAndLength, tableName, dbKeyRoute);
                    } else {
                        doRes(fieldMap, " ", "实体与数据表健康。", localFieldAndLength, tableName, dbKeyRoute);
                    }
                }
                result.put(entryName, fieldMap);
            }
        } catch (Exception e1) {
            logger.error("KN_异常: {}", e1.getMessage(), e1);
        }
        return result;
    }

    private static void doRes(Map<String, Object> fieldMap, String expSql, String message, Map<String, Integer> problemFields, String tableName, String dbKeyRoute) {
        fieldMap.put("status", !StringUtils.hasText(expSql));
        fieldMap.put("sql", expSql);
        fieldMap.put("message", message);
        fieldMap.put("table_name", tableName);
        fieldMap.put("checkFields", problemFields.keySet());
        fieldMap.put("dbKeyRoute", dbKeyRoute);
    }

}

2.采用工具类获取

代码如下(示例):

package rea5.cosmic.debug.bamp.mservicehelper.mservice;

import cfca.org.slf4j.Logger;
import cfca.org.slf4j.LoggerFactory;
import kd.bos.algo.DataSet;
import kd.bos.algo.Row;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.dataentity.metadata.dynamicobject.DynamicPropertyCollection;
import kd.bos.db.DB;
import kd.bos.db.DBRoute;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.EntityType;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.property.TextProp;
import kd.bos.servicehelper.MetadataServiceHelper;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CheckDBServiceHelper {
    private static final Logger logger = LoggerFactory.getLogger(CheckDBServiceHelper.class);

    public Map<String, Map<String, Object>> checkDB(String entityName) {
        Map<String, Map<String, Object>> result = new HashMap<>();
        try {
            //MainEntityType entityType = EntityMetadataCache.getDataEntityType(entityName);
            MainEntityType mainEntityType = MetadataServiceHelper.getDataEntityType(entityName);
            //返回结果
            Map<String, EntityType> allEntities = mainEntityType.getAllEntities();//单据或者基础资料的所有表信息(包含单据体)
            for (Map.Entry<String, EntityType> allEntitiesInformation : allEntities.entrySet()) {
                Map<String, Object> fieldMap = new HashMap<>();
                String dbKeyRoute = "";//数据库路由
                String tableName = "";//表名
                String entryName = "";//实体标识
                DynamicPropertyCollection fields = null;//属性
                EntityType tableInformation = allEntitiesInformation.getValue();//单个表的信息
                // 获取 DynamicObjectType 类的所有字段
                Field[] dynamicObjectTypeFields = DynamicObjectType.class.getDeclaredFields();
                Field[] entityTypeFields = EntityType.class.getDeclaredFields();
                // 合并数组
                Field[] combinedFields = Stream.concat(Arrays.stream(dynamicObjectTypeFields), Arrays.stream(entityTypeFields))
                        .toArray(Field[]::new);
                for (Field field : combinedFields) {
                    field.setAccessible(true); // 设置字段可访问
                    try {
                        Object value = field.get(tableInformation);
                        String name = field.getName();
                        switch (name) {
                            case "dbRouteKey":
                                // 代码块
                                dbKeyRoute = value.toString();
                                break;
                            case "_tableName":
                                // 代码块
                                tableName = value.toString();
                                break;
                            case "_name":
                                // 代码块
                                entryName = value.toString();
                                break;
                            case "_properties":
                                // 代码块
                                if (value instanceof List) {
                                    @SuppressWarnings("unchecked")
                                    DynamicPropertyCollection castedFields = (DynamicPropertyCollection) value;
                                    fields = castedFields;
                                }
                                break;
                            default:
                                // 默认代码块
                                break;
                        }
                    } catch (IllegalAccessException ex) {
                        logger.error("KN_无法访问字段: {}", ex.getMessage(), ex);
                    }
                }
                //执行SQL
                if (!tableName.isEmpty()) {
                    String sql = "SELECT data_type,table_schema,table_name,column_name,character_maximum_length FROM information_schema.columns " +
                            "WHERE table_schema = 'public'AND data_type IN ('character varying', 'character') and table_name = ?";
                    DataSet rows = DB.queryDataSet(this.getClass().toString(), DBRoute.of(dbKeyRoute), sql, new String[]{tableName.toLowerCase()});
                    //数据库字段和长度的map集合
                    Map<String, Integer> DBFieldAndLength = new HashMap<>();
                    for (Row row : rows) {
                        DBFieldAndLength.put(row.getString("column_name"), row.getInteger("character_maximum_length"));
                    }
                    //实体标识和长度的map集合
                    Map<String, Integer> localFieldAndLength = new HashMap<>();
                    assert fields != null;
                    fields.forEach(item -> {
                        String alias = item.getAlias();
                        if (StringUtils.hasText(alias) && item instanceof TextProp) {
                            localFieldAndLength.put(alias, ((TextProp) item).getMaxLenth());
                        }
                    });
                    //有问题的字段集合
                    Map<String, Integer> problemFields = new HashMap<>();
                    //对比字段
                    localFieldAndLength.forEach((itemKey, itemValue) -> {
                        Integer DBValueData = DBFieldAndLength.get(itemKey);
                        if (DBValueData != null && DBValueData.compareTo(itemValue) != 0) {
                            problemFields.put(itemKey, itemValue);
                        }
                    });
                    //生成扩容sql
                    if (!problemFields.isEmpty()) {
                        StringBuilder expSql = new StringBuilder("ALTER TABLE ");
                        expSql.append(tableName);
                        //字段个数
                        List<String> sqlList = problemFields.keySet().stream()
                                .map(item -> " ALTER COLUMN " + item + " TYPE character varying(" + problemFields.get(item) + ")")
                                .collect(Collectors.toList());
                        expSql.append(String.join(",", sqlList));
                        doRes(fieldMap, expSql.toString(), String.format("存在以下字段:%s 实体与数据库长度不一致。", String.join(",", problemFields.keySet())), localFieldAndLength, tableName, dbKeyRoute);
                    } else {
                        doRes(fieldMap, " ", "实体与数据表健康。", localFieldAndLength, tableName, dbKeyRoute);
                    }
                }
                result.put(entryName, fieldMap);
            }
        } catch (Exception e1) {
            logger.error("KN_异常: {}", e1.getMessage(), e1);
        }
        return result;
    }

    private static void doRes(Map<String, Object> fieldMap, String expSql, String message, Map<String, Integer> problemFields, String tableName, String dbKeyRoute) {
        fieldMap.put("status", !StringUtils.hasText(expSql));
        fieldMap.put("sql", expSql);
        fieldMap.put("message", message);
        fieldMap.put("table_name", tableName);
        fieldMap.put("checkFields", problemFields.keySet());
        fieldMap.put("dbKeyRoute", dbKeyRoute);
    }

}

总结

1、采用缓存在效率上有一定的提升,但是缓存采用的是懒加载,一旦页面数据未加载,将获取不到对应的数据。

2、工具类采用直接查询数据库的方式,所以性能上存在一些出入,但是此方案会更加稳定。

当你已经知道了,并想要找到该所在的数据称时,在不同的数据管理系统 (DBMS) 中有不同的方法可以实现这一目标。 以下是几种常见 DBMS 的解决方案: ### MySQL 在MySQL中,你可以通过查询`information_schema.tables`视图来获取有关所有的信息。使用下面的 SQL 查询可以帮助你定位特定所属的数据: ```sql SELECT table_schema AS database_name FROM information_schema.tables WHERE table_name = 'your_table_name'; ``` 将 `'your_table_name'` 替换为你所知道的具体即可得到结果。 ### PostgreSQL 对于PostgreSQL而言,则可以通过查询系统目录pg_tables: ```sql SELECT schemaname, tablename FROM pg_tables WHERE tablename='your_table_name'; ``` 这会返回包含指定格的所有模式(schema),通常公共方案(public schema)是最常用的。 ### Microsoft SQL Server 而在Microsoft SQL Server环境下,我们同样能够利用信息架构视图(information_schema): ```sql USE master; GO SELECT TABLE_CATALOG AS DatabaseName FROM [YourDatabase].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'YourTableName' ``` 请注意这里需要先切换到master数据去执行这个命令,同时把 `[YourDatabase]` 和 `YourTableName` 换成实际值。 ### SQLite SQLite并没有直接提供这样的功能,因为它的设计是一个轻量级、文件级别的存储引擎,默认情况下每个SQLite文件就是一个独立的小型"数据". 因此如果你是在处理SQLite环境下的情况,那么只要你知道了文件位置基本上也就明确了它属于哪一个“”。 以上就是针对不同类型的关系型数据如何根据已知查找其所在数据的一些基本指导。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值