软件开发基础问题之动态的数据结构(下)

本文介绍了处理动态数据的三种方法:有限数据由列转行、无限数据json压缩和检索字段数据同步。通过数据模板和json转换,实现了动态数据的存储和检索。同时,强调了设计的重要性,好的设计能够提高系统的扩展性。最后,提到了动态类型及数据模板绑定的后续讨论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我使用以下3个方法解决动态数据数据问题。

一、有限数据由列转行(数据模板)

有限数据指属性的所有可能值,如上面那篇文章中说到的品牌、适用年龄、尺码等属性,这些属性的特点是数据有限,变动频繁,所以,我们不使用固定的数据表列,而是使用数据表行的无限延申来进行动态拓展,数据模板的实体类属性定义如下:


    private List<String> preinstallValues=new ArrayList<>();//可能的值选项(单选、多选用到)
    @Enumerated(EnumType.STRING)
    private ControlClassifyEnum controlClassifyEnum;//控件类型,如前端需要显示成文本框、日历选择框、单选多选框。
    
    @Enumerated(EnumType.STRING)
    private DataClassifyEnum dataClassifyEnum;//可能的值Object("Object"),字符串型("java.lang.String"),布尔型("java.lang.Boolean"),日期型("java.util.Date"),整型("int"),长整型("long"),单精度浮点型("float"),双精度浮点型("double"),大字符串型("bigString"),自定义("custom");
    
    @ManyToOne
    private DictionaryEntity parentDictionary;//父模板、树形结构需要
    @OneToMany(cascade = {CascadeType.REMOVE},mappedBy="parentDictionary")
    private List<DictionaryEntity> childDictionarys=new ArrayList<>();//子模板、树形结构需要
    @Id
    @Column(length=50)
    private String uuid;//主键
    private String name;//模板名
    private String flag;//模板标识
    private String intro;//模板描述
    private int priority;//排序

以上数据模板我使用jpa实现,其实和实现方式一点关系没有(所以,软件设计不必拘泥于具体实现方案,重点在于设计,好的设计扩展性好,差的设计拓展性差,和具体语言、具体实现方式无关)

采用如上方式可以将无限的数据可能已数据库行的形式呈现,页面添加数据模板(也可叫数据字典)如下图所示

二、无限数据json压缩

由上一步实现的数据模板是一个树形结构,一个项目有共同使用这一颗数据模板数,每个使用的实体类截取其中一个部分(这里涉及到动态的类型及数据绑定,请关注后续文章),截取的部分其实就是一个包含子模版的DictionaryEntity,其中包含了具体的模板值,可以将其json化后转换为一个json字符串,存储到指定的数据库表列字段中,即完成了数据模板的实例化过程。

三、检索字段数据同步

以上两个步骤解决了动态数据的设计和实例化,但存储具体数据的json字符串本压缩成一个字段存储在数据列中,虽然json可以被检索,但效率不高,那么如何处理需要检索的数据,这里使用java的反射来将json字段的值映射到具体的数据库表列字段中。

反射的主要代码如下:

大概的意思就是将resource的数据模板json字段取出,转化为SJONArray,使用递归的方式循环遍历数据模板,使用反射取出resource的类属性,与数据模板的模板flag进行对比,如果相等则对其赋值,大家也可以有自己的实现方式。
    public void recursion(JSONArray arr,Resource resource) 
    {
        for(Object obj : arr)
        {
            JSONObject json=(JSONObject)obj;
            Object child=json.get("childDictionaryInstances");
            if(child!=null)
            {
                recursion((JSONArray)child, resource);
            }
            System.out.println(obj.getClass().getSimpleName());
            if(obj.getClass().getSimpleName().equals("JSONArray"))
            {
                recursion((JSONArray)obj,resource);
            }
            String dictionaryUuid=json.get("dictionaryUuid").toString();
            System.out.println("dictionaryUuid:"+dictionaryUuid);
            DictionaryEntity dictionary=em.find(DictionaryEntity.class, dictionaryUuid);
            String flag=dictionary.getFlag();
            Object dictionaryValue=json.get("dictionaryValue");
            if(!dictionaryUuid.isEmpty()&&!flag.isEmpty()&&dictionaryValue!=null)
            {
                
                //Field[] fields=Class.forName(targetClassifyEnum.getIntro()).getDeclaredFields();
                Field field=null;
                try{
                    System.out.println("Class:"+resource.getClass().getName());
                    field=resource.getClass().getDeclaredField(flag);
                }
                catch(NoSuchFieldException e)
                {
                    System.out.println("flag:"+flag+" 字段不存在,将在父类中查找");
                    try{
                        System.out.println("parent Class:"+resource.getClass().getSuperclass().getName());
                        field=resource.getClass().getSuperclass().getDeclaredField(flag);
                    }
                    catch(NoSuchFieldException ex)
                    {
                        System.out.println("flag:"+flag+" 字段不存在,将在父类中查找");
                    }
                }
                //Field[] fieldsx=field.getDeclaringClass().getDeclaredFields();
                
                if(field!=null)
                {
                    System.out.println("同步字段"+flag+" value:"+dictionaryValue.toString());
                    if(dictionary!=null)
                    {
                        DataClassifyEnum dataClassifyEnum=dictionary.getDataClassifyEnum();
                        if(dataClassifyEnum.equals(DataClassifyEnum.字符串型)||dataClassifyEnum.equals(DataClassifyEnum.大字符串型))
                        {
                            dictionaryValue = dictionaryValue.toString();
                        }
                        else if(dataClassifyEnum.equals(DataClassifyEnum.整型))
                        {
                            dictionaryValue = Integer.parseInt(dictionaryValue.toString());
                        }
                        else if(dataClassifyEnum.equals(DataClassifyEnum.日期型))
                        {
                            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            dictionaryValue = sdf.parse(dictionaryValue.toString());
                        }
                        else if(dataClassifyEnum.equals(DataClassifyEnum.布尔型))
                        {
                            dictionaryValue = Boolean.parseBoolean(dictionaryValue.toString());
                        }
                        field.setAccessible(true);
                        field.set(resource,dictionaryValue);
                        this.update=true;
                    }
                }
            }
        }
    }

这样一来,对于需要检索的数据(其实不多),可以通过数据同步的方式将其同步到数据库列字段中。

总体概括一下,对于动态的数据类型,我们归纳为两类,一类是描述型、一类是描述检索型,对于描述性,定义好数据模板并实例化到具体实体类即可,对于描述检索型,额外需要做一次数据同步来解决。

对于实例化时如何截取指定的数据模板,设计动态类型及类型—数据模板绑定,这个在后续的文章进行说明。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值