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
Typeorm relationships – save by id
Try the author in this way
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
updated create method