TypeORM @ManyToMany() 使用示例

TypeORM 中的 @ManyToMany 装饰器用于定义多对多关系。下面是一个简单的示例:

假设我们有两个实体,一个是用户(User),一个是角色(Role),它们之间有多对多关系。一个用户可以有多个角色,一个角色可以被多个用户拥有。

首先,我们需要在 User 实体和 Role 实体之间使用 @ManyToMany 装饰器来定义多对多关系,同时还需要使用 @JoinTable 装饰器来指定关联表的名称和字段

import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm';
import { Role } from './Role';

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

  @Column()
  name: string;

  @ManyToMany(type => Role, role => role.users)
  @JoinTable()
  roles: Role[];
}

import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from 'typeorm';
import { User } from './User';

@Entity()
export class Role {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @ManyToMany(type => User, user => user.roles)
  users: User[];
}

上面的代码定义了 User 和 Role 实体之间的多对多关系。@ManyToMany 装饰器中,第一个参数是关联实体的类型,第二个参数是反向关联字段。

@startuml

!theme plain
top to bottom direction
skinparam linetype ortho

class role {
   name: varchar(255)
   id: int
}
class user {
   name: varchar(255)
   id: int
}
class user_roles_role {
   userId: int
   roleId: int
}

user_roles_role  -[#595959,plain]-^  role            : "roleId:id"
user_roles_role  -[#595959,plain]-^  user            : "userId:id"
@enduml

使用这些实体,我们可以通过创建和查询用户、角色和它们之间的关联来管理多对多关系。例如,下面的代码演示了如何创建一个用户和一个角色,并将它们关联起来。


    const role1 = roleRepo.create({ name: 'role1' });
    const role2 = roleRepo.create({ name: 'role2' });
    await roleRepo.save([role1, role2]);

    const user1 = userRepo.create({ name: 'user1', roles: [role1] });
    const user2 = userRepo.create({ name: 'user2', roles: [role1, role2] });
    await userRepo.save([user1, user2]);

    const foundUser1 = await userRepo.findOne({ where: { name: 'user1' }, relations: ['roles'] });
    const foundUser2 = await userRepo.findOne({ where: { name: 'user2' }, relations: ['roles'] });

    console.log("foundUser1 :",foundUser1);
    console.log("foundUser2 :",foundUser2);

output


foundUser1 : User { id: 1, name: 'user1', roles: [ Role { id: 1, name: 'role1' } ] }
foundUser2 : User {
  id: 2,
  name: 'user2',
  roles: [ Role { id: 1, name: 'role1' }, Role { id: 2, name: 'role2' } ]
}

在 TypeORM 中,当你从数据库中检索实体时,你可以使用 relations 属性来指定要同时加载的关联实体。

在这个例子中,relations: ['roles'] 的作用是告诉 TypeORM 要同时加载每个用户的角色信息。由于用户和角色是多对多的关联关系,因此加载这些关联实体需要执行额外的查询。使用 relations 属性可以确保这些关联实体也被加载,以便在后续的代码中可以访问它们。

查找角色为 role1 的所有用户

你可以使用 typeorm 的查询构建器(query builder)来查找角色为 role1 的所有用户,例如:


    // 查找角色为 role1 的所有用户
    const role1Users = await userRepo
        .createQueryBuilder('user')
        .innerJoin('user.roles', 'role')
        .where('role.name = :roleName', { roleName: 'role1' })
        .getMany();

这会返回所有具有 role1 角色的用户。