TypeOrm 不会在更新时保存实体及其关系

Posted

技术标签:

【中文标题】TypeOrm 不会在更新时保存实体及其关系【英文标题】:TypeOrm doesn't save entity with it's relation on update 【发布时间】:2020-01-01 16:58:02 【问题描述】:

给定以下关系:

@Entity(name: 'accounts')
export class Account 

  @PrimaryGeneratedColumn('uuid')
  id: string;

  @OneToOne(type => Address, address => address.id)
  @JoinColumn(name: 'address_id')
  address: Address;

  @Column()
  name: string;

和地址关系:

@Entity(name: 'addresses')
export class Address 

  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column(length: 45)
  country: string;

当我通过这个获得account 实体时:

  /**
   * Gets account by haccount ID with ALL relations
   * @param accountId The account ID
   */
  public async getAccountByAccountIdWithRelations(accountId: string): Promise<Account> 
    return await this.findOneOrFail(id: accountId, relations: ['address']);
  

我得到了完整的 Account 实体,其中包含 Address 关系。

然后当我执行以下操作时:

account.address.country = 'newcountry';

然后在accountRepository 中执行this.save(account),地址根本不会更新!

当我在保存前做控制台日志时,我看到 account 实体的地址已更新,所以这真的很奇怪!

为什么会这样?

注意:所有查询都在一个事务中完成;我不知道这是否重要

【问题讨论】:

【参考方案1】:

在 sql 上进行这种更新非常复杂,即使使用 queryBuilder TypeORM 也不支持连接更新(您可以看到它here)。关系选择器非常有用,但我建议您在真正需要时使用它,并添加一个可为空的字段来获取地址的 Id 并单独获取地址,这样在您需要更改的情况下,事情会变得容易得多关系可以说当你想改变整个地址对象。这将是关系中的结果:

@Entity(name: 'accounts')
export class Account 

  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column( nullable: true )
  address_id: string;

  @OneToOne(type => Address, address => address.id)
  @JoinColumn(name: 'address_id')
  address: Address;

  @Column()
  name: string;

您可以像以前一样继续调用该关系:

public async getAccountByAccountIdWithRelations(accountId: string): Promise<Account> 
    return await this.findOneOrFail(id: accountId, relations: ['address']);
  

使用这种方法可以使插入和更新变得容易,并且它也适用于 oneToMany => manyToOne 关系

【讨论】:

【参考方案2】:

应该设置级联。以下是我的实体示例:

@Entity()
@Index([ 'studyId', 'teamId', 'enterdate' ])
export class DataMessage extends BaseEntity 
    @PrimaryGeneratedColumn('increment') id: number;

    @CreateDateColumn() enterdate: Date;
    @UpdateDateColumn( select: false )
    updatedAt?: Date;
    @Column() owner: string;
    @Column() studyId: number;
    @Column() teamId: number;
    @Column() patient: string;
    @Column() orderId: number;
    @Column( default: DataMessageStatus.OPEN )
    status: DataMessageStatus;

    @Column()
    @Index()
    resultId: number;

    @OneToMany(() => DataMessageContent, (c) => c.message,  cascade: true )
    contents: DataMessageContent[];


@Entity()
export class DataMessageContent extends BaseEntity 
    @PrimaryGeneratedColumn('increment') id: number;

    @CreateDateColumn() enterdate: Date;
    @Column() owner: string;
    @Column() role: UserRole;
    @Column( default: MessageStatus.UNREAD )
    status: MessageStatus;

    @Column() txt: string;

    @ManyToOne(() => DataMessage, (m) => m.contents)
    message: DataMessage;

这也应该适用于一对一关系。

【讨论】:

你能在你的答案周围添加更多上下文吗? 我添加了一个完整的例子 对了,cascade让它递归删除保存,谢谢!

以上是关于TypeOrm 不会在更新时保存实体及其关系的主要内容,如果未能解决你的问题,请参考以下文章

TypeORM:保存时无法读取未定义的属性“inverseJoinColumns”

Typeorm - 无法更新实体,因为实体中未设置实体 ID

如何在typeORM中保存@ManyToMany中的关系

TypeORM 保存嵌套对象

TypeORM/MySQL:无法删除或更新父行:外键约束失败

在 Nest JS / TypeORM 中使用具有关系的实体内部的实体并填充数据库