V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
feeeff
V2EX  ›  问与答

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

  •  
  •   feeeff · 330 天前 · 529 次点击
    这是一个创建于 330 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    image

    teacher 的数据表为

    image

    我现在想查询 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 代码,发现又能正常获取数据,想问下大家是什么原因呢?

    image

    12 条回复    2023-05-26 13:37:40 +08:00
    hua123s
        1
    hua123s  
       330 天前 via iPhone
    id 字符串?换成 number 试试呢
    feeeff
        2
    feeeff  
    OP
       330 天前
    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
        3
    feeeff  
    OP
       330 天前
    @hua123s 感谢你的回答,我刚刚试了你的方法,还是不行,结果如下图

    ![image]( https://github.com/wojiaofengzhongzhuifeng/study/assets/25478678/3ad51978-7208-4991-8d34-9e0d97fdc01a)
    hua123s
        4
    hua123s  
       330 天前 via iPhone
    这段代码似乎是使用 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
        5
    lovedebug  
       330 天前
    1. 需要同时使用 ManyToOne 和 OneToMany 的注解
    2. 用 getMany()替代 getOne()
    feeeff
        6
    feeeff  
    OP
       330 天前
    @hua123s

    按照提示的结果如下

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

    只返回的 store ( 1 表)的字段,teacher ( N 表)的字段不返回
    feeeff
        7
    feeeff  
    OP
       330 天前
    @lovedebug

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

    2. 结果如下:


    ![image]( https://github.com/wojiaofengzhongzhuifeng/study/assets/25478678/01958564-4ee4-416a-b244-2946ec2bfaf8)
    lovedebug
        8
    lovedebug  
       330 天前
    @feeeff 建议在 nestjs 中给 typeorm 启动 sql 查询日志
    hua123s
        9
    hua123s  
       330 天前 via iPhone
    @feeeff 看起来你的问题应该用 getRaw ,当然一般而言不会像你这样写。所以你这样,我很陌生。
    feeeff
        10
    feeeff  
    OP
       329 天前
    @hua123s 用 getRawOne ok 了,之前的代码我是通过 chatgpt 生成的,他用的是 getOne
    hua123s
        11
    hua123s  
       329 天前
    其实我的回答是错误的。我问了 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
        12
    feeeff  
    OP
       326 天前
    @hua123s @lovedebug 非常感谢你们的帮助!问题已经解决,getOne => getRawOne 即可
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1024 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 20:01 · PVG 04:01 · LAX 13:01 · JFK 16:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.