Ben Beri
Ben Beri

Reputation: 1201

TypeOrm doesn't save entity with it's relation on update

Given the following relation:

@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;
}

And the addres relation:

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

  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({length: 45})
  country: string;
}

When I get the account entity by this:

  /**
   * 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']});
  }

I get the full Account entity with the Address relation in it.

And then when I do the following:

account.address.country = 'newcountry';

and do this.save(account) in accountRepository the address won't update at all!

When I do console log before the save, I see the account entity with the updated address, so this is something really strange!

Why is it happening?

Note: All queries are done in a transaction; I dont know if it matters

Upvotes: 5

Views: 20883

Answers (2)

tano
tano

Reputation: 2817

The cascade should be set. Here is an example of mine entities:

@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;
}

This should also work for onetoone relation as well.

Upvotes: 2

RalphJS
RalphJS

Reputation: 533

Doing that kind of update on sql is quite complicated and even with queryBuilder TypeORM doesn't support join updates (you can see it here). The relation selector is quite helpfull but I would advise you to use it when its really necesary and add a nullable field to get the Ids of the address and obtain the address on separate it makes the things a lot easier in cases you need to change that relation lets say when you want to change the whole address object. this would be the result in the relations:

@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;
}

And you can keep calling the relation as you did before with:

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

Using this aproach would keep inserting and updating easy and it works also in the oneToMany => manyToOne Relations too

Upvotes: 0

Related Questions