Reputation: 259
When a new user signs up, I want to create a number of relations to be automatically be set up as well. Currently, I am doing it this way:
const user = await User.create({
email,
password: hashedPassword,
}).save();
const settings = await Settings.create({
userId: user.id,
}).save();
const settings = await Profile.create({
userId: user.id,
}).save();
From what I've read, transactions are the best way to handle dependant operations, but PG doesn't create user ID until it is saved.
This is the best I could come up with transactions:
const user = await User.create({
email,
password: hashedPassword,
}).save();
const settings = await Settings.create({
userId: user.id,
});
const profile = await Profile.create({
userId: user.id,
});
await getConnection().transaction(async (transactionalEntityManager) => {
await transactionalEntityManager.save(settings);
await transactionalEntityManager.save(profile);
});
However, there is still the possibility that the user saves, but the relations do not.
Is there a better (or easier way) to handle this?
user.entity.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id!: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@Column({ unique: true })
email!: string;
@Column()
password!: string;
@OneToOne(() => Settings, (settings) => settings.user)
settings: Settings;
@OneToOne(() => Profile, (profile) => profile.user)
profile: Profile;
}
settings.entity.ts
@Entity()
export class Settings {
@PrimaryColumn()
userId: number;
@OneToOne(() => User, (user) => user.settings)
user: User;
}
profile.entity.ts
@Entity()
export class Profile {
@PrimaryColumn()
userId: number;
@OneToOne(() => User, (user) => user.profile)
user: User;
}
Upvotes: 1
Views: 6123
Reputation: 4444
The save
method loads the relations before INSERT
, therefore it is not possible to perform save
for settings
, The generated query will first try to SELECT
the user
and only then INSERT
settings
, as you said - inside a transaction it is not possible to select uncommitted records, and that why it doesn't work.
What can be done? Two options:
const user = await getConnection()
.transaction((transactionalEntityManager) => {
const userObj = User.create({
email,
password: hashedPassword,
})
userObj.profile = Profile.create({});
userObj.settings = Settings.create({});
return transactionalEntityManager.save(User, userObj);
});
settings
and profile
const userInsertResult = await getConnection()
.transaction(async (transactionalEntityManager) => {
const userInsertResult = await transactionalEntityManager
.createQueryBuilder(User,'user')
.insert()
.into(User)
.values({
email,
password: hashedPassword
}).execute();
const settingsInsertResult = await transactionalEntityManager
.createQueryBuilder(Settings,'settings')
.insert()
.into(Settings)
.values({
userId: userInsertResult.raw.id
}).execute();
const profileInsertResult = await transactionalEntityManager
.createQueryBuilder(Profile,'profile')
.insert()
.into(Profile)
.values({
userId: userInsertResult.raw.id
}).execute();
return userInsertResult
});
Upvotes: 1