四赤阳阵の多表视图

四赤阳阵是一种结界忍术,比“四紫炎阵”强上数十倍,必须要四位影级人物同时发动。

视图和四赤阳阵非常像,一般视图由多个表组成一个整体进行展示。

数据库View的概念

  • 传统DB视图,主要用于多表内容聚合展示,不支持直接基于视图进行新增和修改。
  • 视图的主要作用是聚合查询,并不是为了自动关联修改。

需求的合理性

  • 1V1关联表,可以直接操作
  • 1VN or NVN 关联,仅提供查询,不应该提供编辑功能

即使隔着屏幕,我仿佛也能感受到你们有些茫然的样子

但是,相信看完这以下介绍您就会理解。

什么是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);
	}

如上是不是分分钟搞定,复杂的多表业务逻辑!

文章导航