【问题标题】:TypeORM - using take/limit with leftJoinAndSelect isn't working as expectedTypeORM - 对 leftJoinAndSelect 使用 take/limit 不能按预期工作
【发布时间】:2019-06-07 17:30:35
【问题描述】:

我尝试通过 QueryBuilder 获取关系表,它工作正常,直到我尝试使用跳过/偏移和采取/限制。我期待这样的回报:

[
    {
        "id": 1, // order.id
        "locations": [ ... ] array of locations with same order.id
    },
    {
        "id": 2,
        "locations": [ ... ]
    },
    {
        "id": 3,
        "locations": [ ... ]
    }
]

order.entity.ts

@PrimaryGeneratedColumn({ name: 'id' })
public id!: number;

@OneToMany((type) => Location, (location) => location.order, {
    onDelete: 'NO ACTION',
    onUpdate: 'NO ACTION',
})
public locations: Location[];

locations.entity.ts

@PrimaryGeneratedColumn({ name: 'id' })
public id!: number;

@ManyToOne((type) => Order, (order) => order.locations, {
    nullable: false,
    onDelete: 'NO ACTION',
    onUpdate: 'NO ACTION',
})
  @JoinColumn({ name: 'order_id' })
  public order: Order = null;

[Query A] 我使用以下代码获得了所需的输出:(但不使用跳过/获取,输出位于此问题的顶部)

const orders = getRepository(Order)
    .createQueryBuilder('order')
    .where('order.customer_id = :customer', { customer: user.id })
    .leftJoinAndSelect('order.locations', 'location', 'location.order_id = order.order_id')
    .getMany(); // output count is 35, output count with limit/take of 10 would be 10

[查询 B] 如果我添加跳过/偏移和采取/限制,它将如下所示:

const orders = getRepository(Order)
    .createQueryBuilder('order')
    .where('order.customer_id = :customer', { customer: user.id })
    .leftJoinAndSelect('order.locations', 'location', 'location.order_id = order.order_id')
    .skip(0)
    .limit(10)
    .getMany(); // output count is 5

但是在这里,输出是正确的,但长度/计数是完全错误的。 查询 A 找到 35 个订单,其中始终包含 2 个位置。如果我从 Query A 中删除 leftJoinAndSelect 并添加 skip and take,那么它也会找到 35 个订单。但是 Query B,限制/取值为 10,输出计数为 5。它是输出的一半!如果 limit/take 等于 8,则输出长度为 4。它是输出的一半!显然,getMany 有一些魔力,所以我找到了 getRawMany,它使输出加倍。因为对于每个订单,有 2 个位置。这也不是我需要的。而且这个输出的结构也是错误的(如下所示)。 getManyRaw 没问题,但如果我将它与 skip/take 一起使用则不行,因为输出显然是错误的,因为我需要每个订单的所有位置。 Group By 在这里没有帮助,因为这样我每个订单只有 1 个位置。

getRawMany 的输出是这样的

[
    {
        "order_id": 1,
        "locations_id": 100
    },
    {
        "order_id": 1,
        "locations_id": 101
    },
    {
        "id": 2,
        "locations_id": 102
    },
    {
        "id": 2,
        "locations_id": 103
    },
    {
        "id": 3,
        "locations_id": 104
    },
    {
        "id": 3,
        "locations_id": 105
    }
]

正如我所说,在这里使用 skip/take 会给我一个错误的结果。我怎样才能达到我的预期输出?

【问题讨论】:

    标签: typeorm


    【解决方案1】:

    我希望我得到了您的问题,基本上您想要实现的是跳过并接受父订单,而不管它有多少子位置。这是正确的吗?

    如果我的理解是正确的,你可以使用这样的方法:

    const orders = getRepository(Order) // use await if it inside async function
            .createQueryBuilder('order')
            .addSelect('@row_number := ' +
                    'CASE WHEN @parent_id <> location.order_id ' +
                      'THEN @row_number + 1 ' +
                      'ELSE @row_number END AS rn, ' +
                  '@parent_id := location.order_id'
             )
            .where('order.customer_id = :customer', { customer: user.id })
            .leftJoinAndSelect('order.locations', 'location', 'location.order_id = order.order_id')
            .innerJoin('(SELECT @row_number := 0)', 'init_row', '1 = 1')
            .innerJoin('(SELECT @parent_id := 0)', 'init_id', '1 = 1')
            .orderBy('location.order_id')
            .having('rn <= 10')
            .getMany(); // now output should be 10 in case u want to skip use rn > 10 AND rn <= 20 condition
    

    【讨论】:

    • 为了使其适用于可为空的关系,请在 WHEN 子句 OR location.order_id IS NULL 中添加额外条件,并将排序部分替换为 .orderBy('ISNULL(location.order_id)')
    猜你喜欢
    • 1970-01-01
    • 2012-06-29
    • 2015-06-26
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多