TypeOrm 不会在更新时保存实体及其关系
TypeOrm doesn't save entity with it's relation on update
给定以下关系:
@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
实体和更新的地址,所以这真的很奇怪!
为什么会这样?
注意:所有的查询都是在一个事务中完成的;不知道有没有关系
在 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 关系
应该设置级联。这是我的实体的示例:
@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;
}
这也适用于一对一关系。
给定以下关系:
@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
实体和更新的地址,所以这真的很奇怪!
为什么会这样?
注意:所有的查询都是在一个事务中完成的;不知道有没有关系
在 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 关系
应该设置级联。这是我的实体的示例:
@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;
}
这也适用于一对一关系。