Search code examples
node.jstypescripttypeorm

TypeScript, TypeORM, @OneToMany: constructor simply does not work


I'm trying to create two Entities with a one-to-many relationship between them, using node.js, typescript and typeorm. The entities in question are "Movie" and "MovieVote". Code is as follows.

Movie entity:

import {Column, Entity, JoinColumn, OneToMany, PrimaryGeneratedColumn} from 'typeorm';
import { ApiModel, ApiModelProperty } from 'swagger-express-ts';
import { MovieVote } from "~/entities/MovieVote";
import { Genre } from './Genre';

@Entity()
@ApiModel({
  description: 'The movie entity.',
  name: 'Movie',
})
export class Movie {
  @PrimaryGeneratedColumn()
  id?: number;

  @Column({ length: 50 })
  @ApiModelProperty({
    description: 'The title of the movie',
  })
  title: string;

  @Column({ length: 250 })
  @ApiModelProperty({
    description: 'The description of the movie',
  })
  description: string;

  @Column({ length: 50 })
  @ApiModelProperty({
    description: 'The director of the movie',
  })
  director: string;

  @Column({ enum: Genre, type: 'enum' })
  @ApiModelProperty({
    description: 'The genre of the movie',
  })
  genre: Genre;

  @OneToMany(() => MovieVote, movieVote => movieVote.movie)
  votes: MovieVote[];

  constructor(title: string, description: string, director: string, genre: Genre) {
    this.title = title;
    this.description = description;
    this.director = director;
    this.genre = genre;
    this.votes = [];
  }
}

MovieVote entity:

import {Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn} from 'typeorm';
import { ApiModel, ApiModelProperty } from 'swagger-express-ts';
import { User } from "~/entities/User";
import { Movie } from "~/entities/Movie";

@Entity()
@ApiModel({
  description: 'The movie vote entity.',
  name: 'MovieVote',
})
export class MovieVote {
  @PrimaryGeneratedColumn()
  id?: number;

  @Column()
  @ApiModelProperty({
    description: 'The vote value'
  })
  value: number;

  @ManyToOne(() => User)
  @ApiModelProperty({
    description: 'The user responsible for the vote'
  })
  user: User;

  @ManyToOne(() => Movie, movie => movie.votes)
  // @ApiModelProperty({
  //   description: 'The movie the user has voted on'
  // })
  @JoinColumn({name : 'movieId'})
  movie: Movie;

  constructor(user: User, movie: Movie, value: number) {
    this.value = value;
    this.user = user;
    this.movie = movie;
  }
}

What happens is when I try to run the code, it gives me the following error:

Error starting server, Error: Array initializations are not allowed in entity relations. Please remove array initialization (= []) from "Movie#votes". This is ORM requirement to make relations to work properly. Refer docs for more information.

The problem seems to be inside the Movie entity constructor. I can't initialize the relationship "votes" inside the entity with "= [];", but I don't know how it should be done. Also, there is basically no mention of this on typeorm's documentation.

Why is there no example of an Entity constructor with this type of OneToMany relationship on the whole documentation, is beyond me, but I digress. Any help would be welcome, thank you in advance!

P.S.: I've commented the @ApiModelProperty annotation on MovieVote because for reasons unknown this also crashes with a "_decorator error" and something related with undefined properties.


Solution

  • The problem is the this.votes = [].

    Generally, the constructor for entities don't pass any values in and shouldn't set any values. TypeORM will handle creating everything for you.

    If you need to be able to construct your own instances of the class using new you can do something like what I do and change to something like the following.

      constructor(title?: string, description?: string, director?: string, genre?: Genre) {
        if (title) {
          this.title = title;
          this.description = description;
          this.director = director;
          this.genre = genre;
          this.votes = [];
        }
      }