在SqlSugar的开发框架中增加对低代码EAV模型(实体-属性-值)的WebAPI实现支持

笔记哥 / 04-23 / 43点赞 / 0评论 / 867阅读
### 1、SqlSugar开发框架的设计思路 SqlSugar的开发框架本身主要是基于常规关系型数据库设计的框架,支持多种数据库类型的接入,如SqlServer、MySQL、Oracle、PostgreSQL、SQLite等数据库,非关系型数据库的MongoDB数据库也可以作为扩展整合到开发框架里面。 SqlSugar的开发框架本身设计是支持多终端的接入的,支持Winform、WPF、Vue3+ElementPlus、H5的APP应用等多终端的接入的,而Winform、WPF由于运行在客户端的,因此可以自由切换基于本地数据库还是Web API的服务接入,界面呈现效果一致。 ![](https://cdn.res.knowhub.vip/c/2504/23/21018c19.png?G1AAAMTsdJxIPiK026hD2jvFHc3AQhJBpZb1es9Z%2byb6fhcWjc9offr%2b8Gvr06lWKyQsmRWhSwI0p0sZAQqrUgxxDQc%3d) 对于数据的访问,我们设计开关变量模式来自由切换本地数据库模式或Web API的访问方式。如下所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/609481ba.png?G1EAAMTsdJxI8pKi26hD2jvFHc3AQhpBpZb1es9Z%2byb6fgdD4zNan74%2f%2fNr6dCrlygSGcUIIMDFmhmUNUlHVahGJazg%3d) ### 2、EAV模型的设计思路 EAV模型(实体-属性-值)的处理,主要是用来解决动态定义业务表和数据存储和查询的解决方案,我们可以通过动态定义表和字段信息的方式,实现低代码甚至零代码的设计方案。 对于业务表,我们在系统中利用界面动态定义信息即可。如下面是产品信息表的定义界面,定义表和字段的相关信息即可。 ![](https://cdn.res.knowhub.vip/c/2504/23/0bfa016b.png?G1AAAMTsdJxIfEmi26hD2jvFHc3AQhJBpZb1es9Z%2byb6fgcjx2e0Pn1%2f%2bLX16WQmSmBkVoTONTFS0aoSAIgVuTSu4Q%3d%3d) 然后通过配置菜单入口,给出了一个常规的数据录入管理界面,如下所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/1d7ac2c0.png?G1EAAMTsdJzIJ6Ki26hD2jvFHc3AQhpBpZb1es9Z%2byb6fheIxme0Pn1%2f%2bLX16WR2FRKIoiAEVIYkMTUEzpYSa9Ya13A%3d) 上面的字段录入,支持文本、数值、字典选择、单选框、复选框、日期、系统表选择(包括用户、角色、机构、定义表)、附件列表等内容的录入,基本覆盖了常规的需求,特殊需求进行一定的定制化处理即可。 而对于有些业务的主从表处理,如订单和订单明细,也可以通过配置的方式实现界面的自动处理。 ![](https://cdn.res.knowhub.vip/c/2504/23/9bc72e14.png?G1EAAMTsdJzISyWi26hD2jvFHc3AQhpBpZb1es9Z%2byb6fmdwjs9offr%2b8Gvr08lMCzE4oyAE1ISrIAssJNGqpiIa13A%3d) 动态化的数据,查询是其中一个难题,EAV模型(实体-属性-值)他的数据是根据不同的类型进行定义的,不会把所有的内容放在字符型的里面存储,因此保留了字段的原生类型,写入到MongoDB的非关系型数据库中,可以很好的支持各种复杂的查询处理。 ![](https://cdn.res.knowhub.vip/c/2504/23/295c95e5.png?G1AAAER17rxgXUEZfice0wSBBJuBhSSCSi3r9fz%2f2pfI%2bznBHO%2fR%2bvT94dfWp4vZWYTggYzQmZQATFMJGVVNKy2u4Q%3d%3d) 由于我们的表字段是动态化构建的,因此查询字段就也就需要动态化了,我们把查询字段通过列表选择的方式,条件根据不同的数据类型,创建不同的输入控件来实现查询处理。 ![](https://cdn.res.knowhub.vip/c/2504/23/81400023.png?G1EAAMTydJz4%2b%2fOQbqMO3yaKRJuBhTSCSi3r9fz%2fPpfI%2bzlBi%2ffsY%2fn58Gsfy6W1UoVghiEEJiUMtWQELUxqBmrc0wE%3d) 或者 ![](https://cdn.res.knowhub.vip/c/2504/23/ce270660.png?G1AAAMTsdJxIfBK026hD2jvFHc3AQhJBpZb1es9Z%2byb6fgdD4zNan74%2f%2fNr6dKo1FwLDWBE6JIHVOCcJKCJFLrG4hgM%3d) 通过下拉列表的方式选择不同的字段进行查询,如果是数值型或者日期,我们可以根据不同类型来创建输入控件组,来实现区间数值或者日期的输入。 ![](https://cdn.res.knowhub.vip/c/2504/23/39ec4f83.png?G1EAAETn9LyUQhDZvtMdbIlTE20GFtIIKrWs13vO2jfR94dAND%2bj9Rn7w6%2btzyB3qyQQRUEKXFjUtCo8MYQNfLHnNQI%3d) ![](https://cdn.res.knowhub.vip/c/2504/23/7e69be63.png?G1EAAMTsdJxIEvmi26hD2jvFHc3AQhpBpZb1es9Z%2byb6fldWi89offr%2b8Gvr06mUK5OyGgMhCEQtAxUlCKoKUJPENRw%3d) 有时候,为了方便,还提供了一个自定义条件查询的处理功能,可以自由组合多个条件进行数据的查询过滤。 ![](https://cdn.res.knowhub.vip/c/2504/23/9680a54c.png?G1AAAMTsdJxI8kK026hD2jvFHc3AQhJBpZb1es9Z%2byb6fgdD4zNan74%2f%2fNr6dKq1GIGhbAidL%2bFUMrIgiJpUBlJcwwE%3d) 我们参考了[magento](https://github.com/magento/magento2)的eav模型设计图,对不同数据类型的内容进行了独立的存储。 ![](https://cdn.res.knowhub.vip/c/2504/23/a709357b.png?G1EAAMTmtHFS4MR3G%2b1Am1g10WZgIY2gUst6vffu04i%2b38BQ%2f8w%2blp0Pv%2faxjEpJmcCIrHABQQAW1qROKueMGhH8ngY%3d) 由于实体类型(表定义)、实体字段属性、实体记录、字段复制映射关系、属性操作日志、删除日志等表联合构成了一个完整的裸条,如下所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/41dabc9e.png?G1EAAMT0bJxoe1XENvqh%2f4lHQjOwkEZQqWW93nv3aUTf72Ck%2bMw%2blp8Pv%2faxnGrNhcAwTggBKgBM1DiIZYZotRL3dA%3d%3d) 如果我们MongoDB的数据记录移除了,还可以根据关系表的记录和属性值信息,进行MongoDB数据的同步记录处理,这样就可以还原MongoDB的数据记录了,如下所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/95a85564.png?G1AAAMTsdJxI8gml26hD2jvFHc3AQhJBpZb1es9Z%2byb6fgfD4jNan74%2f%2fNr6dColXwRGYkPoUIGyKKqFZFaqZENcwwE%3d) ### 3、基于WebAPI的支持实现 在SqlSugar开发框架中,我们是以接口来串起来整个应用的架构的,并且我们通过泛型基类的封装和集成,极大的减少常规代码的编写。 我们只需要在基类函数里面定义好相关的标准处理:如增、删、改、查、分页、导入、导出、排序等通用接口,以及针对不同业务模块,提供一个接口的扩展和实现即可,如下设计图所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/9c9d3d9d.png?G1EAAMTsdJxIPhG026hD2jvFHc3AQhpBpZb1es9Z%2byb6fheWFJ%2fR%2bvT94dfWp1OtuZCwGCtCEAOgCkMJAqBcNVuOazg%3d) 一个良好的产品,可能往往需要支持多种数据库的接入,根据实际业务的需要进行调整,有时候可能需要2到3种数据库的支持。 ![](https://cdn.res.knowhub.vip/c/2504/23/fc90ee4c.png?G1EAAMTW3DgpL0BY22gDdWfqnTUDC2kElVrW6%2fn%2ftS%2bi9wsGa75H6zP2h19bn0G1Hk4MNghSYCsQNxHVVACH%2bamW1wg%3d) SQLSugar的表和字段信息,都是通过特性描述的方式定义的,它们在不同的数据库是通用的,而我们要做的就是在启动的时候,加载不同的数据库连接字符串,进行初始化即可 而对应Web API的代理调用类,那么为了极大的重用常规的接口处理,我们需要类似的继承关系。 ![](https://cdn.res.knowhub.vip/c/2504/23/813e136d.png?G1AAAMTsdJxIPJK026hD2jvFHc3AQhJBpZb1es9Z%2byb6fgcjx2e0Pn1%2f%2bLX16WQmSmAgAaGjJGHNApWAKuVirhbXcA%3d%3d) 对于BS的前端和移动端,我们根据框架后端的接口进行前端JS端的类的封装处理,引入了ES6类的概念实现业务基类接口的统一封装,简化代码。 ![](https://cdn.res.knowhub.vip/c/2504/23/14d9955f.png?G1AAAMTydJz4%2b5N6uo06fJsoEpqBhSSCSi3r9Z6z9i3y%2fU4Q8RmtT98ffm19upSSTQgChtA16UVLVllDqSBUM%2bIaDg%3d%3d) 这样不管对于终端的调用(Vue3的TS客户端、WInform端、WPF端、Python前端后端)都是以一定的基类抽象的方式,尽可能的封装相同逻辑接口的实现,通过泛型类的引入,可以非常弹性化接口的实现处理。 我们根据接口的定义,分别实现WebAPI的控制器实现部分,以及ApiCaller的客户端调用的封装处理部分,如下所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/005e9a55.png?G1AAAGSd87yg07bxO%2fGoJggk0AwsJBFUalmv95y1b4DvT0bW%2bozWZ%2b4Pv7Y%2bEyLMgZEvVJTOQiyiTmglXITQSOoaCQ%3d%3d) Web API的部分如下所示。 ![](https://cdn.res.knowhub.vip/c/2504/23/da2a7e88.png?G1AAAMTsdJxI8hK026hD2jvFHc3AQhJBpZb1es9Z%2byb6fgdD4zNan74%2f%2fNr6dKo1FwLDWBE6kiAVLWwIpnIhq1hcwwE%3d) Web API部分的路由是Restful的格式命名,然后根据实际的接口定义参数入口即可,如果是复杂实体对象的传递,一般用POST方式。 Web API的ApiCaller调用封装类,主要就是调用基类实现数据的调用和解析处理即可。如对于字段属性的ApiCaller的接口调用封装,如下所示。 主要就是根据Web API的路由名称和参数,以及请求方式的处理即可。 ![](https://cdn.res.knowhub.vip/c/2504/23/e4ba1c39.png?G1EAAER17rxgowOpfice0wSBBJuBhTSCSi3r9fz%2f2pfI%2bzkUOd6j9en7w6%2btTxfyqAJF0YwQYAlWjDwRklYjay6Mazg%3d) 由于Winform或者WPF的调用是基于接口的处理方式,它实际的调用是根据开关变量的参数配置进行选择的。 ```csharp //根据条件获取分页记录或者全部记录 var result = await BLLFactory.Instance.MongoGetList(pageDto); var dataTable = result.Items; if (pageDto.IsPaging) { this.pager1.PagerInfo.RecordCount = result.TotalCount;//记录总行数 } ``` 因此在Winform端或者WPF端,我们开发代码的时候,不用管它来自哪里,都是统一的模型调用处理。 以上就是我们SqlSugar开发框架的多接入方式、多端接入的实现思路,以及EAV实体属性值模式实现数据的弹性化定义以及查询、存储的处理。