Search code examples
nestjstypeormtypeorm-datamapper

Can I use one class as Entity and ViewEntity


I'm working with Typeorm using MySQL database. I have a class as Entity and another class as ViewEntity. The question is why I need two separate Classes when they serve the same goal. Could I use the same Class with Entity and ViewEntity decorators?

Example Entity of Person class:

@Entity()
export class Person {
    @PrimaryGeneratedColumn({ type: 'int', unsigned: true })
    id: number;
    @Column({length:50})
    name: string;
    @Column({type:'date'})
    birthDate: string;
}

Another class for ViewEntity with the same properties added age property:

ViewEntity({
    expression: `SELECT id, name, birthDate, 
                 TIMESTAMPDIFF(YEAR,birthDate,CURDATE()) AS age FROM person;`
})
export class PersonView {
    @ViewColumn()
    id: number;
    @ViewColumn()
    name: string;
    @ViewColumn()
    birthDate: string;
    @ViewColumn()
    age: number;
}

To reduce redundant why I can't combine these two classes by doing this:

@Entity()
@ViewEntity({
    name: 'PersonView',
    expression: `SELECT id, name, birthDate, 
                     TIMESTAMPDIFF(YEAR,birthDate,CURDATE()) AS age FROM person;`
})
export class Person{
    @ViewColumn()
    @PrimaryGeneratedColumn({ type: 'int', unsigned: true })
    id: number;

    @ViewColumn()
    @Column({length:50})
    name: string;

    @ViewColumn()
    @Column({type:'date'})
    birthDate: string;

    @ViewColumn()
    age: number;
}

I searched in Typeorm documentation but they use a class only for ViewEntity. When I tried to test that I face a problem:

DataTypeNotSupportedError: Data type "" in "Person.age" is not supported by "mysql" database.

Also, how would I retrieve data? By doing dataSource.getRepository(Person) Person class has Entity and ViewEntity decorator then which type of entity will be retrieved? How would Typeorm distinguish between these two entities?


Solution

  • After a while, I figured out a half solution because we still need two classes (apparently necessary to distinguish between the Table and the View). But without duplicated properties.

    I used extends and Yes it works:

    @Entity()
    export class Person{
        @ViewColumn()
        @PrimaryGeneratedColumn({ type: 'int', unsigned: true })
        id: number;
    
        @ViewColumn()
        @Column({ length: 50 })
        name: string;
    
        @ViewColumn()
        @Column({ type: 'date' })
        birthdate: string;
    }
    
    
    @ViewEntity({
        expression: `SELECT id, name, birthdate, 
                     TIMESTAMPDIFF(YEAR,birthDate,CURDATE()) AS age FROM person;`
    })
    export class PersonView extends Person {
        @ViewColumn()
        public age: number;
    }