Pierre_T
Pierre_T

Reputation: 1302

TypeORM PostgreSQL @ManyToOne save violates not-null constraint

I have a basic nestjs app with 3 entities :

This is quite straightforward and the first part of those relations works as expected : I can save new pages doing so :

  async createPage(documentId: number, url: string) {
    const document = await this.documentRepository.findOne({ id: documentId });
    if (document) {
      const pageEntity = new PageEntity();
      pageEntity.imgUrl = url;
      pageEntity.document = document;
      await this.pageRepository.save(pageEntity);
    }
  }

but when I try to apply the same logic to the words/page relation, it fails. I m not sure why this behaves differently

async postWord(pageId: number, word: { text: string }) {
    const page = await this.pageRepository.findOne({ id: pageId });
    if (page) {
      const wordEntity = new WordEntity();
      wordEntity.text = word.text;
      wordEntity.page = page;
      await this.wordRepository.save(wordEntity);
    }
  }

Error Message :

[ExceptionsHandler] null value in column "pageId" of relation "word_entity" violates not-null constraint +107723ms
QueryFailedError: null value in column "pageId" of relation "word_entity" violates not-null constraint

here are the entities declarations :

// document.entity.ts

@Entity()
class DocumentEntity {
  @PrimaryGeneratedColumn()
  public id?: number;

  @Column()
  public name: string;

  @Column()
  public locale: string;

  @Column()
  public pdfUrl: string;

  @Column()
  public folderPath: string;

  @OneToMany(() => PageEntity, (page) => page.document, {
    primary: true,
    eager: true,
    cascade: true,
  })
  public pages?: PageEntity[];
}

export default DocumentEntity;

// page.entity.ts

@Entity()
class PageEntity {
  @PrimaryGeneratedColumn()
  public id?: number;

  @Column({ nullable: true })
  public pageNumber?: number;

  @Column({ nullable: true })
  public text?: string;

  @Column()
  public imgUrl: string;

  @OneToMany(() => WordEntity, (word) => word.page, {
    eager: true,
    onDelete: 'CASCADE',
    primary: true,
  })
  words?: WordEntity[];

  @ManyToOne(() => DocumentEntity, {
    primary: true,
    onDelete: 'CASCADE',
  })
  @JoinColumn()
  public document: DocumentEntity;
}

export default PageEntity;

// word.entity.ts
@Entity()
class WordEntity {
  @PrimaryGeneratedColumn()
  public id?: number;

  @ManyToOne(() => PageEntity, {
    nullable: true,
    primary: true,
    onDelete: 'CASCADE',
  })
  @JoinColumn()
  public page!: PageEntity;

  @Column()
  public text: string;

  @Column({ type: 'decimal', nullable: true })
  public confidence?: number;
}


Upvotes: 0

Views: 5681

Answers (2)

RomainGuarinoni
RomainGuarinoni

Reputation: 1

You need to remove the primary: true from your @ManyToOne relation because a primary relation cannot be set as NULL

Upvotes: 0

Hossein Heydari
Hossein Heydari

Reputation: 1549

Try this:

@Entity()
class WordEntity {
  .....

  @ManyToOne(() => PageEntity, {
    nullable: true,
    primary: true,
    onDelete: 'CASCADE',
  })
  @JoinColumn({
    name: 'pageId',
    referencedColumnName: 'id',
  })
  page?: PageEntity;

  @Column({ nullable: true })
  pageId?: number

  .....

}

async postWord(pageId: number, word: { text: string }) {
      const wordEntity = new WordEntity();
      wordEntity.text = word.text;
      // check if the pageId exists, maybe inside Dto with a decorator
      wordEntity.pageId = pageId;
      await this.wordRepository.save(wordEntity);
  
  }

Upvotes: 4

Related Questions