[TOC=3] > ![](https://box.kancloud.cn/d378f9e8f9b184b4bea76a622179de9f_341x201.png) > 四赤阳阵是一种结界忍术,比“四紫炎阵”强上数十倍,必须要四位影级人物同时发动。 视图和四赤阳阵非常像,一般视图由多个表组成一个整体进行展示。 ### 数据库View的概念 * 传统DB视图,主要用于多表内容聚合展示,不支持直接基于视图进行新增和修改。 * 视图的主要作用是聚合查询,并不是为了自动关联修改。 ### 需求的合理性 * 1V1关联表,可以直接操作 * 1VN or NVN 关联,仅提供查询,不应该提供编辑功能 即使隔着屏幕,我仿佛也能感受到你们有些茫然的样子 ![](https://box.kancloud.cn/7aee62f28419dd8bff2c7357ca856faa_208x159.png) 但是,相信看完这以下介绍您就会理解。 ### 什么是1V1关联表? ~~~ SELECT `users`.`id` AS `id`, `users`.`status` AS `status`, `users`.`login_id` AS `login_id`, `users`.`login_pwd` AS `login_pwd`, `users`.`nickname` AS `nickname`, `users`.`reg_time` AS `reg_time`, `users`.`info` AS `info`, `users_exp`.`users_id` AS `users_id`, `users_exp`.`exp` AS `exp`, `users_exp`.`avg` AS `avg`, `users_exp`.`qq` AS `qq` FROM (`users` JOIN `users_exp`) WHERE ( `users`.`id` = `users_exp`.`users_id` ) ~~~ 上面的视图就是 users 1V1 users_exp ,关联条件是 ``users`.`id` = `users_exp`.`users_id`` 所以称之为1V1关联,因为用户和用户扩展信息表是通过user id 进行关联的,一个对一个。 **反之除了1V1,其它的都是1VN or NVN** 在进行非1V1业务时,比如:老师和学生 老师有N个学生 学生有N个老师 学生列表 | ID | 姓名 | 我最喜欢的老师 | | --- | --- | --- | | 1 | 张三 | 熊雯 | ID和姓名来自学生表,我的老师的名字来自老师表,通过中间关系表,多表联查形成上面的列表。 但是修改这个列表的时候,显然不能直接将老师的名字给改了并且更新到老师表中。 合理的需求是,可以修改学生的姓名,学生和老师的关系。 但你不能直接改老师名字,你能喜欢英语老师,别人也可以喜欢,你改了名,别人还咋喜欢,都不认识了。 好吧,扯这么多,就是希望大家不要在使用视图的时候陷入误区。 * * * * * 再看一个段子: 问程序员,你会啥? 我会增删改查。 问程序员,软件是啥? 软件除了增删改查,还是增删改查。 貌似听起来没啥毛病吧? * * * * * 在实际企业级项目中,很少有功能模块是纯单表操作的,多多少少关联其它表的某些字段。 这时候除了增删改查,就是复杂的增删改查了,不是单表的增删改查。 一个业务,需要操作3张以内的表,我们可以简单的说这是一个简单的功能。 一个业务,需要操作5张以内的表,我们还可以说这是一个简单的功能吗。 5张表意味着什么? 5表联查,5表更新,5表。。。。尼玛想想都疼蛋。。。 > PS:所以在设计表结构的时候不要将关系复杂化,应该遵循大事化小小事化了的原则,该冗余的地方就冗余,不要盲目套三大范式,你设计的表是给人用的,不是给老师打分的。 但是往往,肯定会遇到一小波业务就是有那么复杂,需要三表,甚至更多的表,联合作业。 甚至在复杂业务的系统里,这是家常便饭? 怎么破? > 在经历了很多方案的来回推倒,重写,来回折腾之后最终决定如下! > 以下方案完全是在无尽的折磨中,尝试出来的,没有参考任何第三方系统和设计,如果雷同,纯属山寨! > 至于下述方案到底能支撑什么样的业务场景,各位智者见智,应该拥有无限可能! ### EOVA视图处理的设计 V1.6 * 目的:让操作多表,像操作单表一样简单 ### 使用思路 * 自建View 提供 元数据导入,支撑复杂的列表查询展现 * 复杂表单后端逻辑通过Aop增强(配合DIY_JS 操控前端) * 超复杂的自定义按钮,自定义前端Form和后端逻辑 导入视图和导入普通数据表一样,没有什么特殊的地方! 列表查询和展现也没有什么特殊的地方 一个是form table 一个是form view 需求背景描述: 代码: com.oss.order.OrderIntercept By V1.6 OSS Demo 订单关联用户和收获地址: orders 订单表 users 用户表 address 收获地址表 下面主要描述核心的也是最复杂多变的地方. 新增AOP: ~~~ /** * 推荐使用Model来实现业务逻辑,万物皆对象,不要问我为什么! */ @Override public String addBefore(AopContext ac) throws Exception { Record data = ac.record; // 获取用户信息 保存 Users user = RecordUtil.peelModel(Users.class, data, "login_id", "nickname", "info"); user.save(); int uid = user.getInt("id"); LogKit.info("新增用户成功:" + user.getInt("id")); // 获取收获信息 保存 Address address = RecordUtil.peelModel(Address.class, data, "name", "full", "mobilephone"); address.save(); int aid = address.getInt("id"); LogKit.info("新增收获信息成功:" + aid); Orders order = RecordUtil.peelModel(Orders.class, data); order.set("address_id", aid); order.set("create_user_id", uid); order.set("update_user_id", uid); order.set("create_time", new Date()); order.set("update_time", new Date()); order.save(); LogKit.info("新增订单信息成功:"); return super.addBefore(ac); } ~~~ 修改AOP: ~~~ /** * 懒人做法Record,一条龙全部搞定,简单粗暴! */ @Override public String updateBefore(AopContext ac) throws Exception { Record r = ac.record; // 获取用户信息 更新 Record user = RecordUtil.peel(r, "create_user_id -> id", "login_id", "nickname", "info"); Db.update("users", user); int uid = user.getInt("id"); LogKit.info("更新用户成功:" + uid); // 获取收获信息 更新(下面的特殊语法可自行研究源码) Record address = RecordUtil.peel(r, "address_id -> id", "name", "full", "mobilephone"); Db.update("address", address); int aid = address.getInt("id"); LogKit.info("更新收获信息成功:" + aid); Db.update("orders", r); LogKit.info("更新订单信息成功:"); return super.updateBefore(ac); } ~~~ > 如上是不是分分钟搞定,复杂的多表业务逻辑!