skip to Main Content

I’m learning NestJS with TypeORM (PostgreSQL) and trying to create a library website for practice.

Here are my entities, Book and Author. An author can have multiple books, but each book can belong only to one author.

import { Author } from 'src/author/entities/author.entity';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Book {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @ManyToOne(() => Author, (author) => author.books)
  author: Author;

  @Column()
  summary: string;

  @Column()
  isbn: string;
}
import { Book } from 'src/book/entities/book.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Author {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @OneToMany(() => Book, (book) => book.author)
  books: Book[];
}

Here are the DTOs:

export class CreateBookDto {
  title: string;
  author: number;
  summary: string;
  isbn: string;
}
export class CreateAuthorDto {
  firstName: string;
  lastName: string;
}

And here’s the method that adds a new Book to the database:

import { Injectable } from '@nestjs/common';
import { CreateBookDto } from './dto/create-book.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Book } from './entities/book.entity';
import { Repository } from 'typeorm';

@Injectable()
export class BookService {
  constructor(
    @InjectRepository(Book) private readonly bookRepository: Repository<Book>,
  ) {}

  create(createBookDto: CreateBookDto) {
    return this.bookRepository.save(createBookDto);
  }
}

A typical request would look like this:

{
  title: "Example Book Title",
  author: 1,
  summary: "Example Book Summary",
  isbn: "978-3-16-148410-0"
}

The author should already be in the database and would be selected with a prefilled <select> tag, for example. The number is that author’s id in the database table.

I think there’s something wrong with my DTOs or the way I’m creating a new Book, because typescript is giving me this error for this.bookRepository.save(createBookDto);:

No overload matches this call.
  Overload 1 of 4, '(entities: DeepPartial<Book>[], options?: SaveOptions | undefined): Promise<(DeepPartial<Book> & Book)[]>', gave the following error.
    Argument of type 'CreateBookDto' is not assignable to parameter of type 'DeepPartial<Book>[]'.
      Type 'CreateBookDto' is missing the following properties from type 'DeepPartial<Book>[]': length, pop, push, concat, and 29 more.
  Overload 2 of 4, '(entity: DeepPartial<Book>, options?: SaveOptions | undefined): Promise<DeepPartial<Book> & Book>', gave the following error.
    Argument of type 'CreateBookDto' is not assignable to parameter of type 'DeepPartial<Book>'.
      Type 'CreateBookDto' is not assignable to type '{ id?: number | undefined; title?: string | undefined; author?: DeepPartial<Author> | undefined; summary?: string | undefined; isbn?: string | undefined; }'.
        Types of property 'author' are incompatible.
          Type 'number' is not assignable to type 'DeepPartial<Author> | undefined'.

The error goes away if I do this:

create(createBookDto: CreateBookDto) {
  const book = Object.assign(new Book(), createBookDto)
  return this.bookRepository.save(book);
}

However, I’m not sure if that’s the correct way to create something. I haven’t seen such a pattern yet.

What should I do? How are relations usually handled when creating a new record? Maybe there’s something wrong with author: number in CreateBookDto?

2

Answers


  1. Typeorm relationships – save by id

    author: 1 as any
    

    Try the author in this way

    Login or Signup to reply.
  2. The author property in CreateBookDto is of type number, while the author property in Book is of type Author. TypeScript sees that you’re trying to assign a number (the author’s ID) where it expects an instance of Author, leading to a type mismatch error.

    Here is the updated code

    @Entity()
    export class Book {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      title: string;
      
      @Column()
      authorId: number;
      
      @Column()
      summary: string;
    
      @Column()
      isbn: string;
    
      @ManyToOne(() => Author, (author) => author.books)
      author: Author;
      @JoinColumn({
        name: "authorId",
      })
    }
    export class CreateBookDto {
      title: string;
      authorId: number;
      summary: string;
      isbn: string;
    }

    updated create method

    @Injectable()
    export class BookService {
      constructor(
        @InjectRepository(Book) private readonly bookRepository: Repository<Book>,
      ) {}
    
      create(createBookDto: CreateBookDto) {
    
        // Create a new Book instance
        const book = new Book();
        book.title = "Example Book Title";
        book.authorId = 1;
        book.summary = "Example Book Summary";
        book.isbn = "978-3-16-148410-0";
    
        // Save the new Book
        return this.bookRepository.save(book);
      }
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search