typeorm / typeorm

ORM for TypeScript and JavaScript. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.
http://typeorm.io
MIT License
34.02k stars 6.27k forks source link

Lose database relations when use "loadRelationIds" #7927

Open 5v3n-08 opened 3 years ago

5v3n-08 commented 3 years ago

Lose database relations when use loadRelationIds

Steps to Reproduce

UserEntity:

@Entity({ name: 'users' })
export class User extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id!: string;

 @Column({ type: 'simple-json', default: {} })
  properties!: IProperties;

  @ManyToMany(() => Department, (department) => department.users)
  departments!: Department[] | string[];
}

DepartmentEntity:

@Entity({ name: 'departments', schema: config.database.schema.department })
export class Department extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id!: string;

  @Column()
  name!: string;

  @Column({ type: 'simple-json', default: {} })
  properties!: IProperties;

  // ----- Relations -----
  @ManyToMany(() => User, (user) => user.departments)
  @JoinTable({ name: 'user_has_departments' })
  users!: User[] | string[];
}

Controller:

 const user = await User.findOneOrFail({ where: { id: req.body.id }, loadRelationIds: true });

 if (req.body.points !== undefined) {
   user.properties.points = req.body.points;
 }

 const _user = await user.save();

Expected Behavior

When a model is loaded with loadRelationIds, all relations should be kept when saving without overwriting them.

Actual Behavior

If I save the user model as in the example, all department relations will be deleted.

My Environment

Dependency Version
Operating System docker (macOS)
Node.js version v14.17.3
Typescript version typescript@4.3.4
TypeORM version typeorm@0.2.34

Additional Context

Should this behavior be correct, is there a workaround or a better way? I actually only work with relation ids.

Relevant Database Driver(s)

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

pleerock commented 3 years ago

@imnotjames let's discuss loadRelationIds feature:

However I think sometimes it's useful feature, we just have ugly implementation. Right now I have 3 options in my mind:

  1. fix current @RelationId state and make loadRelationIds to accept @RelationId-marked properties (and map to them):
Department.find({
   loadRelationIds: {
      userIds: true,
      photos: {
          albumIds: true
      }
   }
})

(same as ["userIds", "photos.albumIds"])

  1. forget about relation ids - deprecate and remove this feature, user can simply load relation with "only user id":
DepartmentRepo.find({
   select: {
      users: {
         id: true
      }
   }
})

The result will contain the full "department" (by @future design all columns are selected until at least one column (not relation) isn't specified in the selection) + "users" property with only "id" inside.

I'm more thinking towards #2 because it doesn't bring any new functionality / complexity and does solve the problem of having only relation ids. Plus we don't need to add extra properties into the model.