网站搜索

typescript - TypeORM 更新多对多关系的一部分记录


我在 Channel 和 User 之间有一个多对多的关系,用于向订阅频道的用户发送电子邮件通知。我正在开发一个功能,其中一个频道会被另一个频道取代,但我不知道如何将所有通知从即将解散的频道转移到目标频道。

@Entity()
export class User {
    @PrimaryColumn()
    id: string

    @Column()
    createdAt: Date

    @Column()
    updatedAt: Date

    @Column()
    email: string

    @ManyToMany(_type => Channel)
    @JoinTable()
    notifications: Channel[]
}

@Entity()
export class Channel {
    @PrimaryColumn()
    id: string

    @Column()
    createdAt: Date

    @Column()
    updatedAt: Date
}

async function transferNotifications(from: unknown, to: unknown): Promise<void> {
    //?
}

答案#1

你至少有两个选择:

1. 使用实体管理器

首先,获取所有与 notification 有已解析关系的 User 实体。然后从所有获取到的 User 实体的 notification 属性中删除旧的(已解散的)Channel 实体,如果先前包含旧的实体,再将新的 Channel 实体添加到该数组中。这样会移除对应的关联表行,并在新的频道中添加一行新的记录。

显而易见的缺点是,连接将会在三张表的所有行上执行,所有结果都会加载到应用程序内存中。因此,对于较大的表,这不一定是一个好的解决方案。

2. 使用 QueryBuilder

一个更好的方法是通过添加自定义连接表实体自己构建连接表。然后使用 QueryBuilder 将旧外键替换为新通道的 id。

getRepository(UserChannel).createQueryBuilder()
   .update()
   .set({ channelId: '<new channel id>' })
   .where(`channelId = :channelId`, { channelId: `<old channel id>`})
   .execute();
@Entity()
export class User {

    @PrimaryColumn()
    id: string

    @Column()
    createdAt: Date

    @Column()
    updatedAt: Date

    @Column()
    email: string

    @OneToMany(type => UserChannel)
    userChannels: UserChannel[]
}

@Entity()
export class UserChannel {

    @ManyToOne(type => User)
    user!: User;

    @Column({ primary: true })
    userId!: string;


    @ManyToOne(type => Channel)
    channel!: channel;

    @Column({ primary: true })
    channelId!: string;
}


@Entity()
export class Channel {

    @PrimaryColumn()
    id: string

    @Column()
    createdAt: Date

    @Column()
    updatedAt: Date
}

答案#2

如果你在使用 NodeJs,你可以使用 promises 来进行批量更新、删除或其他操作。

你需要做的是将所有更新 map 到数组中,然后使用 Promise.all 解决它们。

新更新。

updates = [{ id: 1, name: "Channel 1" }, { id: 2, name: "Channel 2"}];

批量更新代码

l

let promises = updates.map(update =>  { 
      let query = {id: update.id};
          delete update.id;
          return channelRepository
              .update({id update.id}, update) 
         });
return await Promise.all(promises);