问一个 Nest TypeORM createQueryBuilder 1:N 查询结果的问题

2023-05-22 21:19:00 +08:00
 feeeff

现有两张表 storeteacher,关系为 1:N ,store 表的数据表为

teacher 的数据表为

我现在想查询 storeId = 1 对应的 teacherName ,我的 createQueryBuilder 代码如下

    const sqlResult =  await this.storeRepository
      .createQueryBuilder('store')
      .innerJoinAndSelect(Teacher, 'teacher', 'store.id = teacher.storeId')
      .select([ 'teacher.name'])
      .where('store.id = :id', {id})
      .getOne()

查询的结果是 null ,我起初以为是我的 createQueryBuilder 代码有问题,所以直接运行 createQueryBuilder 生成的 SQL 代码,发现又能正常获取数据,想问下大家是什么原因呢?

651 次点击
所在节点    问与答
12 条回复
hua123s
2023-05-22 21:29:55 +08:00
id 字符串?换成 number 试试呢
feeeff
2023-05-22 21:30:15 +08:00
append:

store 的表结构定义为

```
@Entity()
export class Store extends BaseEntity{

@Column()
name: string

@Column()
description: string

@OneToMany(()=>Teacher, (teacher)=>teacher.store)
teachers: Teacher[]

}
```


teacher 的表结构定义为

```

@Entity()
export class Teacher extends BaseEntity{

@Column()
name: string


@ManyToOne(() => Store, (store) => store.teachers)
@JoinColumn({ name: "storeId" })
store: Store;

}

```
feeeff
2023-05-22 21:34:20 +08:00
@hua123s 感谢你的回答,我刚刚试了你的方法,还是不行,结果如下图

![image]( https://github.com/wojiaofengzhongzhuifeng/study/assets/25478678/3ad51978-7208-4991-8d34-9e0d97fdc01a)
hua123s
2023-05-22 21:41:29 +08:00
这段代码似乎是使用 TypeORM 进行数据库查询和连接操作。然而,有一个问题在于选择的字段 `'teacher.name'` 并未包含在内连接语句的 ON 条件中。在内连接时,ON 条件用于指定连接两个表的关联条件,以确保只返回符合条件的结果。

在你提供的代码中,使用了内连接 `innerJoinAndSelect()` 来连接 `store` 表和 `teacher` 表,并指定了 `store.id = teacher.storeId` 作为关联条件。然而,在选择字段时,只选择了 `'teacher.name'`,而没有选择 `store` 表中的任何字段。

修复这个问题的方法是在选择字段时,也包括需要的 `store` 表字段,例如 `'store.id'` 或其他相关的字段。修改后的代码如下:

```typescript
const sqlResult = await this.storeRepository
.createQueryBuilder('store')
.innerJoinAndSelect(Teacher, 'teacher', 'store.id = teacher.storeId')
.select(['store.id', 'teacher.name'])
.where('store.id = :id', { id })
.getOne();
```

现在,选择字段中包括了 `store` 表的 `'store.id'` 和 `teacher` 表的 `'teacher.name'`,这样就可以正确地返回结果了。请根据你的需求修改选择的字段,并确保关联条件符合你的数据模型。
太晚了,早点睡吧。
lovedebug
2023-05-22 21:46:44 +08:00
1. 需要同时使用 ManyToOne 和 OneToMany 的注解
2. 用 getMany()替代 getOne()
feeeff
2023-05-22 22:11:13 +08:00
@hua123s

按照提示的结果如下

![image]( https://github.com/wojiaofengzhongzhuifeng/study/assets/25478678/79f09389-2dc2-4de2-a305-ee8617e7e3a2)

只返回的 store ( 1 表)的字段,teacher ( N 表)的字段不返回
feeeff
2023-05-22 22:13:04 +08:00
@lovedebug

1. 我在 entity 同时添加了 OneToMany 和 ManyToOne ,在二楼哈

2. 结果如下:


![image]( https://github.com/wojiaofengzhongzhuifeng/study/assets/25478678/01958564-4ee4-416a-b244-2946ec2bfaf8)
lovedebug
2023-05-22 22:32:12 +08:00
@feeeff 建议在 nestjs 中给 typeorm 启动 sql 查询日志
hua123s
2023-05-22 22:38:01 +08:00
@feeeff 看起来你的问题应该用 getRaw ,当然一般而言不会像你这样写。所以你这样,我很陌生。
feeeff
2023-05-23 13:06:59 +08:00
@hua123s 用 getRawOne ok 了,之前的代码我是通过 chatgpt 生成的,他用的是 getOne
hua123s
2023-05-23 19:24:16 +08:00
其实我的回答是错误的。我问了 GPT4 ,
在这段查询代码中,你没有包含你要查询的 store 实体。虽然你在创建查询时加入了 store ,但在 select 语句中,你并没有显式地包含 store 。如果你希望获取特定的 store 和与其关联的 teacher 的 name ,你需要在 select 语句中指明。

另外,根据 TypeORM 的 API 文档,当你使用 innerJoinAndSelect 函数时,它会自动将你 join 的实体添加到 select 语句中。然而,你在 select 语句中显式地只选择了 'teacher.name',这可能导致 store 实体以及其他教师的信息被排除。

如果你希望获取 store 以及关联的 teacher 的 name ,你可以尝试以下的代码:

javascript
Copy code
const sqlResult = await this.storeRepository
.createQueryBuilder('store')
.innerJoinAndSelect('store.teachers', 'teacher')
.select(['store', 'teacher.name'])
.where('store.id = :id', { id })
.getOne();
这段代码将获取 store 以及其关联的所有教师的名字。注意,innerJoinAndSelect 的参数应当为关联字段的名字,而不是实体类的名字。另外,如果你只关心教师的名字,而不关心其他的字段,那么你可以在 select 语句中显式地选择 'teacher.name'。

如果你仍然遇到问题,那么可能是因为你的实体关系或者数据存在问题。你应该确保你的数据库中 store 和 teacher 之间的关联已经正确地建立,且你查询的 store 的 ID 确实存在,并且有关联的 teacher 。

希望这个答案对你有所帮助!如果你还有其他问题,欢迎你随时提问。
feeeff
2023-05-26 13:37:40 +08:00
@hua123s @lovedebug 非常感谢你们的帮助!问题已经解决,getOne => getRawOne 即可

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/942056

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX