[Bug] Vuetify 在 card 标签中使用 v-for 指令,不能加载出指定部分条目。

80 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

一、问题描述

前端界面使用了vuetify组件,在编写「文章列表」部分时,发现文章不能按照设定的pagesizepagenum展示指定的部分数据,而是一股脑展示了全部数据。

image.png

二、问题分析

1.后台「文章列表」页面正确展示:

image.png

后台「文章列表」页面和出问题的前台页面调用的是同一个API函数。

2.后台「文章列表」页面和UI的请求参数是一致的:

在 Go 后端的「查询文章列表」API函数中埋入print(),
每次调用时打印pagesizepagenum
从前端请求接收到的pagesizepagenum将会传给Model层。

  • 在后台「文章列表」点击分页器第2页第1页

image.png

  • 在前端点击「文章列表」组件的第2页第1页

image.png

3.寻找问题根源

(1) Bug 不在后端,应该是前端`vuetify`的使用出错。
(2) Bug 在后端,但是后台组件`Ant Design Vue`对这个问题进行了容错设计。

使用API工具向后端发送模拟请求,发现不管Querypagesizepagenum设为多少,都返回全部数据。

三、※ 问题解决

修改后端的Model相关函数:
Limit()Offset()挪到Find()Preload()前,问题解决: image.png

另外,由于

 文章 belongs to 分类,属于一对一关系

将原有 Preload() 改为 Joins()单次查询以提高性能。

使用 API 工具,响应无误:

image.png

四、总结与拓展

Bug的出现是因为对GORM的语句链次序不熟悉。

1.关于GormLimitOffset在语句链中的位置问题。

LimitOffset总要放在Find()前面

2. 关于GormPreloadJoins的区别(Joins只是一种特别的Preload):

(1)底层执行的SQL原理不同
Preload 在一个单独查询中加载关联数据,也就是说,当每使用一个Preload('tableName'),底层对 SQL 就新增一条查询语句:

db.Find(&users)
// SELECT * FROM users;

=======3个 Preload() 新增 3 次预加载语句=======
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to

而 Joins 会使用 left join 加载关联数据,可以在 1 条语句中完成。

db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users) 
// SELECT * FROM `users` LEFT JOIN `companies`  ON `users`.`company_id` = `Company`.`id` AND `Company`.`alive` = true;

(2)表关系的适用范围不同
Preload适用于多表的各种关系,包括has onehas manybelongs to等。
Joins只适用于1:1关系,如has onebelongs to关系。

相关阅读: 预加载 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.