Search code examples
mysqltypescripttypeorm

TypeORM repository create not setting values


Here is my entity:

@Entity()
export class Game extends BaseEntity {

     @PrimaryGeneratedColumn({
        name: "id",
     })
     private _id: number;

     @Column({
        name: "name",
        type: "varchar",
        nullable: false,
     })
     private _name: string;


    get id(): number {
        return this._id;
    }

    set id(id: number) {
        this._id = id;
    }

    get name(): string {
        return this._name;
    }

    set name(name: string) {
        this._name = name;
    }
}

And when I try to create a new Game, I want to use Repository API.

So what I do is:

import { getRepository } from "typeorm";
import { Game } from "../entities/game.entity";
import { InsertGameConfig } from "../interfaces/entities/game";

public async insert(config: InsertGameConfig) {
    return await getRepository(Game).create(config).save();
}

And calling insert function like this:

await insert({
  name: "test",
});

But when I check mysql query log, I find this:

INSERT INTO `game`(`id`, `name`) VALUES (DEFAULT, DEFAULT)

However, if I create the instance and set every value like this:

const game = new Game();
game.name = config.name;
return await game.save();

And then it works correctly, so:

INSERT INTO `game`(`id`, `name`) VALUES (DEFAULT, "test")

From TypeOrm doc:

create - Creates a new instance of User. Optionally accepts an object literal with user properties which will be written into newly created user object.

const user = repository.create(); // same as const user = new User();
const user = repository.create({
    id: 1,
    firstName: "Timber",
    lastName: "Saw"
}); // same as const user = new User(); user.firstName = "Timber"; user.lastName = "Saw";

Note

I tried setting class's attributes public, and then create works correctly, but when they're private and I use getters/setters, it does not work.


Solution

  • I've never seen any ORM (in any language) would use an object private fields as data fields. And why would one expect that? Private fields are not visible from any other code except that particular class instance. So, the ORM wouldn't be aware of them and therefore you shouldn't mark them with decorators/attributes, it just doesn't make any sense. Even if the ORM could find private properties how would it guess which getter/setter should have been used with the property _name or any other?

    In the docs they suggest using only classes with plain public properties like this:

    @Entity()
    export class User {
    
        @PrimaryGeneratedColumn()
        id: number;
    
        @Column()
        firstName: string;
    
        @Column()
        lastName: string;
    }
    

    and it seems to be the only correct way at the moment.