如何让 Inner Join 在 TypeORM 上工作?

ico*_*nio 18 typeorm

我正在尝试在 TypeORM 上构建一个简单的查询,但我没有使用 INNER JOIN 获取整个数据。我究竟做错了什么?

SQL 查询运行完美,但 typeorm 只返回“watcher”表的数据。

SQL查询

SELECT *
FROM watcher w
INNER JOIN user
ON w.userId = user.id;
Run Code Online (Sandbox Code Playgroud)

类型ORM

async getSystemWideWatchers(): Promise<any[]> {
    const query = this.createQueryBuilder('watcher');
    const result = await query.innerJoin('user', 'u', 'watcher.userId = u.id').getMany();
    console.log(result)
    return result;
}
Run Code Online (Sandbox Code Playgroud)

Cem*_*Cem 19

TypeORM 有一个名为 的方法innerJoinAndSelect。你用普通的innerJoin. 这就是为什么不从中选择用户表的原因。

一旦您将该部分更改为innerJoinAndSelect,将从中选择监视表。但是,getManygetOne返回具有您的实体类型的对象。因此,如果您的实体类型在用户表和观察者表之间没有关系,则所选列将不会包含在返回的对象中。

在向您展示如何添加这些关系之前,我想提一下,您可以选择使用getRawMany函数来获取所有选定的列,但我不建议使用它,因为关系更加整洁(没有原始列名称,您会得到与关系相对应的实体数组),在您的情况下,没有理由不使用关系。

现在,根据我对数据库设计的理解,您有用户,用户有观察者。一个Watcher只能监视一个User,并且可能有多个Watcher监视同一个用户。

在这种情况下,用户与观察者的关系称为“一对多”。

观察者与用户的关系称为“多对一”。

您需要在您的实体中指定此信息。这是一个例子。注意OneToMany装饰器。

@Entity()
export class User {
    @PrimaryColumn()
    id: number;

    @Column()
    userName: string;

    @OneToMany(type => Watcher, watcher => watcher.user)
    watchers: Watcher[];
}
Run Code Online (Sandbox Code Playgroud)

这是相应的观察者实体:

@Entity()
export class Watcher {
    @PrimaryColumn()
    id: number;

    @Column()
    watcherName: string;

    // we can omit this (and the join condition), if userId is a foreign key
    @Column()
    userId: number;

    @ManyToOne(type => User, user => user.watchers)
    user: User;
}
Run Code Online (Sandbox Code Playgroud)

一旦建立了这些关系,您就可以选择一个用户及其所有观察者,反之亦然(选择一个观察者及其观察的用户)。

以下是执行这两项操作的方法:

// Select a user and all their watchers
const query = createQueryBuilder('user', 'u')
    .innerJoinAndSelect('u.watchers', 'w'); // 'w.userId = u.id' may be omitted
const result = await query.getMany();
Run Code Online (Sandbox Code Playgroud)

(如果您想包含没有观察者的用户,您可以使用 leftJoin 而不是 innerJoin,您可能知道。)

这可能是您最初尝试做的事情:

// Select a watcher and the user they watch
const query = createQueryBuilder('watcher', 'w')
    .innerJoinAndSelect('w.user', 'u'); // 'w.userId = u.id' may be omitted
const result = await query.getMany();
Run Code Online (Sandbox Code Playgroud)

  • 兄弟你懂了!这些实体正是我所拥有的。问题是我尝试使用“user.id”和“watcher.userId”而不是“watcher.user”加入。非常非常感谢你!新年快乐! (2认同)

Ade*_*ani 12

以防万一有人遇到另一种情况。添加到 Cem 的回答中。如果数据库中没有定义关系,那么您可以执行以下操作:

const query = createQueryBuilder('user', 'u')    
.innerJoinAndMapMany(
    'u.ObjectNameToMapDataOn',
    EntityName,// or 'tableName'
    'IAmAlias',
    'u.columnName= IAmAlias.columnName'
  )
Run Code Online (Sandbox Code Playgroud)

类似地,可以使用innerJoinAndMapOne。如果您希望有多个带有连接表的记录或单个记录,取决于您的情况。

  • 谢谢你,这真的很有帮助 (2认同)

小智 8

如果两个表之间没有关系,则必须使用getRow().

getOne()并将getMany()返回具有存储库类型的对象,因此删除连接表的数据

这个例子对我有用:

this.userRepository
            .createQueryBuilder('user')
            .select(['user.username as username', 'o.orderTime as orderTime'])
            .where('user.id = :id', {id})
            .andWhere('o.callerId = :id', {id})
            .innerJoin(OrderEntity, 'o')
            .getRawMany()
Run Code Online (Sandbox Code Playgroud)