question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Not loaded nullable ManyToOne relation comes as null and thus gets removed on save

See original GitHub issue

Issue Description

When loading an entity via SelectQueryBuilder without joining a nullable ManyToOne relation, the returned entity will have the not loaded relation set as null. Now saving again this entity results in removing any possibly attached related entity.

Expected Behavior

Loading an entity without loading a certain relation should always result in undefined (and not null) for this relation, as undefined can be interpreted as “was not loaded” while null should be “was loaded but is NULL in the database”. Thus saving the entity directly after loading it should be a NO-OP.

Actual Behavior

The not loaded relation is automatically assigned the value null on entity retrieval. Thus saving the entity will remove the link between the entity and the relation. Just loading and saving an entity without actively manipulating it changed the state of the database.

Steps to Reproduce

game.entity.ts with nullable ManyToOne relation creator

import { Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { User } from './user.entity';

@Entity()
export class Game {

	@PrimaryGeneratedColumn()
	id!: number;

	// some more relations and columns

	@ManyToOne(() => User, user => user.createdGames, { nullable: true })
	@JoinColumn()
	creator!: User | null;

	@Column()
	finished: boolean;

}

user.entity.ts

import { Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { Game } from './game.entity';

@Entity()
export class User {

	@PrimaryGeneratedColumn()
	id!: number;

	@OneToMany(() => Game, game => game.creator)
	createdGames!: Game[];

}

game.repository.ts

import { EntityRepository, Repository } from 'typeorm';
import { Game } from './game.entity';

@EntityRepository(Game)
export class GameRepository extends Repository<Game> {}

Retrieval of the entity (just in case it might matter, I added the WHEREs and as comment some joins):

const game: Game | undefined = await this.gameRepository
	.createQueryBuilder('g')
	// several innerJoinAndSelect / leftJoinAndSelect here, but none for g.creator
	.where('g.id = :gameId', { gameId })
	.andWhere('g.finished = FALSE')
	.getOne();

If the game with the given id gameId has a creator set in the database, game.creator will be null. (I guess it will always be null).

Thus running

await this.gameRepository.save(game);

will result in an update of the game in the database, setting the foreign key to its creator to NULL.

My Environment

Dependency Version
Operating System Ubuntu 20.04.3 (inside Windows 10 20H2 WSL)
Node.js version 16.13.1
Typescript version 4.4.4
TypeORM version 0.2.38
TypeORM version 0.2.38
@nestjs/typeorm version 8.0.2
@nestjs/core and @nestjs/common 8.1.1

npm ls typescript also shows 4.3.5 as dependency of @nestjs/cli@8.1.4

Relevant Database Driver(s)

DB Type Reproducible
aurora-data-api no
aurora-data-api-pg no
better-sqlite3 no
cockroachdb no
cordova no
expo no
mongodb no
mysql yes
nativescript no
oracle no
postgres no
react-native no
sap no
sqlite no
sqlite-abstract no
sqljs no
sqlserver no

Are you willing to resolve this issue by submitting a Pull Request?

  • ✖️ Yes, I have the time, and I know how to start.
  • ✖️ Yes, I have the time, but I don’t know how to start. I would need guidance.
  • ✖️ No, I don’t have the time, but I can support (using donations) development.
  • ✅ No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
securedirectivecommented, Feb 20, 2022

@Isli-GD Hmm, I haven’t touched any project using typeorm for at least a year. I’ll see if I can get a dev environment up to take a look. At the time, PR #7147 contained all necessary tests to confirm it fixed issue #7146. But it certainly is possible this new issue is related.

0reactions
Isli-GDcommented, Jul 14, 2022

@McP4nth3r not yet. Tests also passed when I tried them, so I think I need to further elaborate on my code and check which additional conditions are necessary to give a MWE that indeed reproduces the behavior I encountered. But I currently have no time, so this might take another month or two, I think.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Nullable @ManyToOne not accepting null value [duplicate]
Meaning I need to reassign a null value before saving the Profile . There is apparently a ticket about this on the github,...
Read more >
Lazy relations resolve to 'undefined' instead of 'null' #7146
After reading about the partial-update feature, where a literal null is required to save NULL to the database, and undefined indicates the field ......
Read more >
The best way to map a @OneToOne relationship with JPA and ...
Learn the best way to map a OneToOne association with JPA and Hibernate when using both unidirectional and bidirectional relationships.
Read more >
Basic Relationship Patterns — SQLAlchemy 2.0 Documentation
The above example shows a many-to-one relationship that assumes non-nullable behavior; the next section, Nullable Many-to-One, illustrates a ...
Read more >
Chapter 2. Mapping Entities - Red Hat on GitHub
A good an complete set of working examples can be found in the Hibernate Annotations ... Note that the logical column name is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found