typeorm手动raw转entity
孙泽辉 Lv5

今天用左连接后,查询平均成绩查不出来,判断是 ORM 在转换成实体类的时候,自动把不认识的字段过滤掉了,想到一解决方案,记录一下。

问题描述

我的在线考试系统,后台老师要统计学生的平均成绩。

想着使用AVG统计平均分,文档说直接addSelect就好了

image

,但 **最后要使用getRawMany**,这样一来,我原本自动RAW到`Entity的转换就无了,变成没有结构的一堆数据,像这样

image

虽然结构很乱,但好歹我的平均分查出来了。

难道我要一个一个地转换?为什么自带了转换我不用我要自己转?

越想越不对劲,最终我想到能不能在·ORM·帮我转换前把平均分记录下来,然后再转换,然后拼接上平均分上去。

实现代码

事实证明是可行的。

根据大佬的代码:

Mapping raw query to entities · Issue #6803 · typeorm/typeorm (github.com)

下面是我的查询所有考试的平均分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// record.service.ts
import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader';
import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader';
import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer';

async findAll(userId: number) {
// 创建 queryBuilder
const qb = this.repo
.createQueryBuilder('e_record')
.addSelect('avg(e_record.score)', 'averageScore')
.where('userId = :userId', { userId })
.orWhere('e_record.relTeacherId = :userId', { userId })
.leftJoinAndSelect(
'e_record.exam_room',
'e_room',
'e_room.id = e_record.examRoomId',
)
.leftJoinAndSelect(
'e_room.for_classes',
'classes',
'classes.id = e_room.for_classes',
)
.leftJoinAndSelect(
'e_record.exam_paper',
'e_paper',
'e_paper.id = e_record.examPaperId',
)
.groupBy('e_record.relTeacherId');
// 直接拿raw,后面转换
const rawResults = await qb.getRawMany();
// 临时保存聚合函数计算的平均分
const avgScoreList = rawResults.map((entity) => ({
id: entity.e_record_id,
score: entity.averageScore,
}));
// 下面这些都是拿到用到的实体信息
const connection = this.repo.manager.connection;
const queryRunner = connection.createQueryRunner();
const relationIdLoader = new RelationIdLoader(
connection,
queryRunner,
qb.expressionMap.relationIdAttributes,
);
const relationCountLoader = new RelationCountLoader(
connection,
queryRunner,
qb.expressionMap.relationCountAttributes,
);
const rawRelationIdResults = await relationIdLoader.load(rawResults);
const rawRelationCountResults = await relationCountLoader.load(rawResults);
const transformer = new RawSqlResultsToEntityTransformer(
qb.expressionMap,
connection.driver,
rawRelationIdResults,
rawRelationCountResults,
queryRunner,
);
// 转换成实体
const transformed = transformer.transform(
rawResults,
qb.expressionMap.mainAlias,
);
return transformed.map((entity) => {
// 将平均分拼接到转换后的实体上
const avgScore =
avgScoreList.find((score) => score.id === entity.id)?.score || 0;
return {
...entity,
avgScore,
};
});
}

查询结果符合我的预期,带结构并且平均分也查出来了

image
 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Total words 85.5k