Search code examples
typescriptpostgresqlnestjsmikro-orm

Trying to persist not discovered entity of type object


The problem

I'm new to Nest.js and Mikro-ORM, which I have to learn as a job requirement.

This stack requires TypeScript, which I despise from the bottom of my heart, but it has to be done.

I have set up my app and when I execute npm run start:dev, it starts up without a problem.

However, when I try to add something to the database, it spazzes out and gives me the following error block:

[Nest] 5368   - 07/03/2021, 11:52:15 PM   [ExceptionsHandler] Trying to persist not discovered entity of type object. +183188ms
ValidationError: Trying to persist not discovered entity of type object.
    at Function.notDiscoveredEntity (/home/lazar/tuts/backend/node_modules/@mikro-orm/core/errors.js:51:16)
    at SqlEntityManager.persist (/home/lazar/tuts/backend/node_modules/@mikro-orm/core/EntityManager.js:438:48)
    at SqlEntityManager.persistAndFlush (/home/lazar/tuts/backend/node_modules/@mikro-orm/core/EntityManager.js:449:20)
    at SqlEntityRepository.persistAndFlush (/home/lazar/tuts/backend/node_modules/@mikro-orm/core/entity/EntityRepository.js:21:23)
    at UsersService.create (/home/lazar/tuts/backend/dist/users/users.service.js:47:35)
    at UsersController.create (/home/lazar/tuts/backend/dist/users/users.controller.js:25:40)
    at /home/lazar/tuts/backend/node_modules/@nestjs/core/router/router-execution-context.js:38:29
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async /home/lazar/tuts/backend/node_modules/@nestjs/core/router/router-execution-context.js:46:28
    at async /home/lazar/tuts/backend/node_modules/@nestjs/core/router/router-proxy.js:9:17

This is my first time walking into this stack and I have no idea what the error means. When I Google this error, I get nothing useful. What can I do to make it go away?

The relevant code

  • The Entity (User.ts)
import { Entity, PrimaryKey, Property } from "@mikro-orm/core";

@Entity()
export class User {
  @PrimaryKey()
  id!: string;

  @Property()
  email!: string;

  @Property()
  name!: string;

  @Property()
  password!: string;

  @Property({ type: 'date' })
  createdAt = new Date()

  @Property({ type: 'date', onUpdate: () => new Date() })
  updatedAt = new Date()
};
  • The Controller (users.controller.ts)
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { CreateUserDTO } from './dto/create-user.dto';
import { User } from './interfaces/user.interface';
import { UsersService } from './users.service';
import { User as UserEntity } from "../entities/User"

@Controller('users')
export class UsersController {
  constructor(private usersService: UsersService) {}

  @Post()
  async create(@Body() createUserDto: CreateUserDTO): Promise<User> {
    console.log("CREATEUSERDTO", createUserDto);
    return await this.usersService.create(createUserDto)
  }
}
  • The Service (users.service.ts)
import { EntityRepository } from '@mikro-orm/core';
import { Injectable } from '@nestjs/common';
import { User } from './interfaces/user.interface';
import { User as UserEntity } from "../entities/User"
import { InjectRepository } from '@mikro-orm/nestjs';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: EntityRepository<UserEntity>
  ) {}

  async create(user: User): Promise<UserEntity> {
    console.log("ALL GOOD");
    const newUser = this.userRepository.create(user)
    console.log("ALL GOOD");
    console.log("NEW USER", newUser);
    await this.userRepository.persistAndFlush(user)
    console.log("ALL GOOD");
    return newUser
  }
}
  • The Module (users.module.ts)
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Module } from '@nestjs/common';
import { User } from 'src/entities/User';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [MikroOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService]
})
export class UsersModule {}
  • The DTO
export class CreateUserDTO {
  readonly name: string;
  readonly email: string;
  readonly password: string;
  readonly createdAt: Date;
  readonly updatedAt: Date;
}
  • The Interface
export interface User {
  id?: string;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
  updatedAt: Date;
}

Solution

  • As Micael Levi already pointed out in the comments, this is caused by you trying to persist a POJO/DTO instead of entity instance.

    const dto = { name: '...', email: '...' };
    const user = em.create(User, dto);
    
    // this is basically what you are doing and will fail as the prototype
    // is just `Object` - which is what you see in the error
    em.persist(dto);
    
    // and this is what you need to do instead
    em.persist(user);
    

    You always need to work with entity instances so the ORM will know what metadata to use. If you have just Object there is no way to associate the object with correct database table.