前面两篇随笔介绍了EAV模型(实体-属性-值)的设计思路和Winform前端对于通用查询的处理,本篇随笔继续深入EAV模型(实体-属性-值)设计的探讨,介绍实体属性的定义,以及根据不同属性的定义构建不同的输入控件处理,以及列表界面的展示。旨在结合关系型数据库的熟练使用、性能优势和MongoDB数据库的弹性化文档处理特点,为低代码的处理方案提供一个实用的思路供参考。
1、实体属性定义
根据实体定义的一些特性,我们设计了下面的定义界面,主要就是对实体类属性的各种类型或者数据关联处理进行更好的维护,以及控制属性的可排序、可查询、是否可用、是否只读、是否隐藏值、是否必填等常规特性。
![](https://file.jishuzhan.net/article/1795660506866913281/f596293836b01e0b162769407a82a861.webp)
在通用的列表展示的时候,我们会根据属性的定义信息来统一展现不同的控件以及相关的属性设置,如常规可以根据储存类型来定义不同的控件输入,如文本、多文本、日期、整形、浮点型等数据,进一步还可以绑定下拉列表(动态字典、静态列表或者在字段自身值列表),也可以选择在选择字典的时候,复制某些值,或者在选择其他业务表的时候,同步复制关联的值等等,以及可以再前端类型进一步细化定义一些类型,如选择系统用户、系统机构、系统角色、查看附件、系统业务编码等等,这些内置的处理能够更贴切的符合实际系统的数据选择需求。
例如对于一些常规的字段属性(如产品名称),我们默认保留存储类型为varchar即可。
![](https://file.jishuzhan.net/article/1795660506866913281/0ae639c87435b5ac981e64f27812f672.webp)
而对于一些需要引用字典信息的,我们可以选择设置系统字典类型,如下所示。
![](https://file.jishuzhan.net/article/1795660506866913281/0d4208164f6222b0f49f18ddc6e2dc34.webp)
而对于需要在数据录入的时候设置为下拉列表的方式(单选或者复选),并指定动态字典的,也可以实现。
![](https://file.jishuzhan.net/article/1795660506866913281/33df2eed17967cd7b97fe98e34bc1894.webp)
前端的输入类型,有复选框、单选框组、评分控件、下拉列表、系统用户、系统角色、系统机构、系统附件、系统业务表编码 等选项,分别对应不同的控件界面录入处理。
我们选中通用的下拉列表,可以进一步指定是单选还是多选,并且数据来源可以为静态、动态、字段所有唯一值等不同的方式。
![](https://file.jishuzhan.net/article/1795660506866913281/db85f8e05b59831059d5692bb0e80f5e.webp)
如果我们定义了很多不同的实体类型业务表,那么如果需要主从表中选择复制某些字段,如何实现呢,通过上面的表选择设置即可实现。
![](https://file.jishuzhan.net/article/1795660506866913281/d7f93cebdcd61971fe4e3e929e8f51cb.webp)
2、WInform前端列表展示和数据录入处理
有了上面的准备定义工作,我们就可以为通用的EAV列表界面展示进行处理了,常规的列表界面分为单业务表的显示(如产品信息),以及主从表的业务显示(如订单和订单明细),如下界面所示。
单业务表的显示(如产品信息)
![](https://file.jishuzhan.net/article/1795660506866913281/e89391196a51edae20c51f8b183ef57a.webp)
可以看到,这个列表的展示和常规开发的业务表显示没有太大的差异,也可以根据字段进行查询,以及进行自定义条件查询、或者进行高级查询。
![](https://file.jishuzhan.net/article/1795660506866913281/7d0074ce8f6425e8abbc9bdf3b2b4258.webp)
![](https://file.jishuzhan.net/article/1795660506866913281/88280cf59c3877cb9f70c48909ed7cc2.webp)
主从表的业务显示(如订单和订单明细)
![](https://file.jishuzhan.net/article/1795660506866913281/0ce3f4f02a96f83114b3909a507ae9ab.webp)
这两种不同的数据展示方式,自动根据系统属性设置关联进行动态创建(在属性定义的时候,指定了包含的明细对象)。
![](https://file.jishuzhan.net/article/1795660506866913281/7662b2756a207e61f30a24b55f33b451.webp)
有了列表信息的动态展示,我们还需要确定每行记录的数据录入控件类型。
前面介绍了界面控件录入的类型,常规可以根据储存类型来定义不同的控件输入,如文本、多文本、日期、整形、浮点型等数据,进一步还可以绑定下拉列表(动态字典、静态列表或者在字段自身值列表),也可以选择在选择字典的时候,复制某些值,或者在选择其他业务表的时候,同步复制关联的值等等,以及可以再前端类型进一步细化定义一些类型,如选择系统用户、系统机构、系统角色、查看附件、系统业务编码等等。
![](https://file.jishuzhan.net/article/1795660506866913281/e862d2a9f0c301ba67babe74c19ab7f8.webp)
对于整数或者带有小数点的浮点数,可以使用SpinEdit的输入来录入数值内容,如下所示,并可以定义设置显示的格式。
![](https://file.jishuzhan.net/article/1795660506866913281/9238844a2fc3552a85ed446fba6c9303.webp)
同理对于日期类型,一样也是构建一个DateEdit控件用来录入数据,如下所示。
![](https://file.jishuzhan.net/article/1795660506866913281/4c3759bcffb3139da048b4ba8014b7b4.webp)
对于一些录入,有时候根据自身字段已有的数据列表进行选择录入,如下所示。
![](https://file.jishuzhan.net/article/1795660506866913281/f2349c35c0fb2409969a679cded44ae4.webp)
这个字段选择的时自身的值列表配置,如下是它的属性定义。
![](https://file.jishuzhan.net/article/1795660506866913281/3c6f9e26e5c98dc86c2ce4ee1d6b7328.webp)
对于复选框、评分控件,也是根据配置信息,构建对应的录入控件的,如下界面所示。
![](https://file.jishuzhan.net/article/1795660506866913281/cd449382655e6e7366a7aa19ccd8ad45.webp)
对于系统用户、角色、机构的选择信息,我们可以根据用户是否允许多选来构建选择界面,定义好选择用户、角色、机构的界面即可,如下所示。
![](https://file.jishuzhan.net/article/1795660506866913281/551e55a824b2f78be499fd466bd673d2.webp)
选择机构的界面如下所示。
![](https://file.jishuzhan.net/article/1795660506866913281/b84416c5ba860b8d4420ab5b63f43761.webp)
选择角色的界面类似(多选出现复选框),如下面所示。
![](https://file.jishuzhan.net/article/1795660506866913281/2496fc42e95d5e3d9b109e16e9f013a3.webp)
我们也可以指定属性为系统的附件,
![](https://file.jishuzhan.net/article/1795660506866913281/4f7c886d25f1f2dad9e7f0a7dcaae06d.webp)
从而在列表显示并编辑的时候,接受系统上传的附件并显示附件的数量
![](https://file.jishuzhan.net/article/1795660506866913281/b0bb673af5367569749b32e96d477d51.webp)
单击按钮,可以打开查看记录的附件的列表信息。
![](https://file.jishuzhan.net/article/1795660506866913281/83d483535d4961405cedc9feef9bdf53.webp)
另外,对于一些业务编码,我们也可以内置进行快速生成,使用系统配置好的生成编码规则,能够更好的符合我们实际的需求。
![](https://file.jishuzhan.net/article/1795660506866913281/77f9c0a79c1b397f68f4fc7082f98db2.webp)
系统业务编码规则管理是我们系统业务中的一个通用模块,可以引用它进行生成即可。
![](https://file.jishuzhan.net/article/1795660506866913281/2bf6a2f49209a4376eba8b7b4bb03e46.webp)
这样我们在创建订单的时候,可以根据这个约定好的规则进行生成订单编码,是不是很方便?
![](https://file.jishuzhan.net/article/1795660506866913281/cd335c8cb290e5c5e0692ac404f44354.webp)
3、动态业务菜单的定义
上面我们介绍了实体类型的属性定义,以及通用的EAV数据列表界面展示,包括单业务列表界面,以及主从表界面的展示,并已经完成了各种常规输入控件类型的处理,包括系统字典、系统用户、系统角色、系统机构、系统附件、系统业务编码规则等,基本上覆盖了我们大多数的业务录入的需求了。
完成了上面的那些工作,我们来考虑动态业务菜单的问题,动态菜单是系统的一个管理模块,管理系统所有可用的菜单,并可以根据不同的角色授权不同的菜单,从而实现更加个性化的系统界面展示。
前面介绍了可以定制不同的业务实体类型,如下界面定义了很多不同的业务实体类型。
![](https://file.jishuzhan.net/article/1795660506866913281/156edd05ec1664858f9670bec93ac38b.webp)
随着我们业务定义的变化,肯定会定义更多的实体类型,那么我们就要考虑动态菜单与具体的业务实体类型结合的问题了。
通过结合一个特定业务的菜单和一个特定的实体类型,我们就可以让系统打开一个业务的列表界面显示,从而实现常规的菜单元素的管理和分配了。
我们改造一下传统的菜单定义,我们只需要确定这个菜单项目为EAV的业务菜单和具体的绑定实体类型ID即可,如下界面所示。
![](https://file.jishuzhan.net/article/1795660506866913281/0362b0098c108b0ca7c3025d7df4478a.webp)
我们通过再菜单编辑/新增界面中,指定菜单为EAV模式菜单,并确定好关联的实体类型ID(可以通过弹出框选择),从而创建一个EAV业务菜单即可。
同理,对于订单和订单明细的主从表列表业务,也是通用的处理方式,如下界面所示。
![](https://file.jishuzhan.net/article/1795660506866913281/acd5b8418aa179ae2f7b1b1a5292c5cf.webp)
这样,我们在动态菜单中单击处理,就可以传递对应的实体类型ID给具体的窗体,并通过实体类型ID进行对应的初始化和显示记录即可,如下是单表的EAV模式的产品信息表的显示和录入处理界面。
![](https://file.jishuzhan.net/article/1795660506866913281/b0205ded626093f003a311e3cacadbc1.webp)
下面则是主从表的(订单和订单明细表)的显示和录入处理界面。
![](https://file.jishuzhan.net/article/1795660506866913281/5e7a301b24743b9217d4048f63f3469a.webp)
这样,通过直接配置而不需要编码,就可以实现常规业务表的设计,并可以结合动态菜单的方式,给客户进行开发,可以快速根据客户的需求进行增加或者修改字段,调整字段录入方式,顺序,可用等等,实现快速开发的响应。
同时,由于数据记录是存储在MongoDB的数据库上,即使数据量很大,也是能够高性能的进行响应,减少了关系型数据库在多表联合的弊端,同时还能利用数据文档的可修改性等突出特点,极大的减少编码的开发出来,可以说基本是零代码的开发方式。
深入一点,我们可以记录每个字段的修改日志,增加每个字段对不同人员的可见性(可访问性)、可修改性等进行控制,从而实现更加弹性化的展示和录入的处理方式。