web-dev-qa-db-fra.com

Comment interroger une relation plusieurs-à-plusieurs avec TypeORM

Note a une relation plusieurs-à-plusieurs avec Subject

Quelle est la meilleure façon de l'interroger? Je voudrais aimer écrire ce qui suit pour obtenir tous les sujets sur une note :

  const subjectRepo = connection.getRepository(Subject);
  const response = await subjectRepo.find({
    relations: ['notes'],
    where: { note }
  });

mais cela renvoie TOUS les sujets, pas seulement les sujets sur la note.

Reln défini comme:

  @ManyToMany(() => Subject, (subject: Subject) => subject.notes)
  subjects: Subject[];

-- et --

  @ManyToMany(() => Note, note => note.subjects)
  @JoinTable()
  notes: Note[];

La requête exécutée est:

SELECT "Subject"."id" AS "Subject_id", "Subject"."name" AS "Subject_name", "Subject"."description" AS "Subject_description", "Subject"."createdDate" AS "Subject_createdDate", "Subject"."updatedDate" AS "Subject_updatedDate", "Subject"."notebookId" AS "Subject_notebookId", "Subject"."measurementsId" AS "Subject_measurementsId", "Subject_notes"."id" AS "Subject_notes_id", "Subject_notes"."content" AS "Subject_notes_content", "Subject_notes"."notedAt" AS "Subject_notes_notedAt", "Subject_notes"."createdDate" AS "Subject_notes_createdDate", "Subject_notes"."updatedDate" AS "Subject_notes_updatedDate", "Subject_notes"."notebookId" AS "Subject_notes_notebookId" FROM "subject" "Subject" LEFT JOIN "subject_notes_note" "Subject_Subject_notes" ON "Subject_Subject_notes"."subjectId"="Subject"."id" LEFT JOIN "note" "Subject_notes" ON "Subject_notes"."id"="Subject_Subject_notes"."noteId"

Remarque: vous pouvez le faire:

  return subjectRepo
    .createQueryBuilder('subject')
    .leftJoin('subject.notes', 'note')
    .where('note.id = :id', { id: note.id })
    .getMany();

Mais j'espère une approche avec moins de chaînes et une jointure explicite

14
Jonathan

Le SQL que vous essayez d'obtenir pour générer TypeORM est à peu près comme suit

SELECT *
FROM subject
JOIN subject_note AS jt on jt.subject_id = subject.id
WHERE jt.note_id = :id

1. Ce n'est pas possible avec repo.find

Au moment de l'écriture, il n'y a aucun moyen de créer une clause where sur une table jointe à l'aide de repo.find(...). Vous pouvez join ( doc ) mais la clause where affecte uniquement l'entité du référentiel.

TypeORM ignore également silencieusement les clauses where invalides, alors faites attention à celles-ci.

2. Sélectionnez à nouveau l'entité note

Si vous voulez tous les subject d'un note donné, vous devrez soit utiliser un générateur de requêtes, comme vous l'avez noté, soit vous devrez resélectionner l'objet note avec ses relations.

note = await noteRepo.find({
    relations: ['subjects'],
    where: { id: note.id }
});
const subjects = note.subjects

3. Utilisez TypeORM relations paresseuses

Si vous voulez éviter une nouvelle sélection, vous devez utiliser TypeORM relations paresseuses mais cela vous oblige à changer le type dans les deux entités pour être un Promise

// note entity
@ManyToMany(() => Subject, (subject: Subject) => subject.notes)
subjects: Promise<Subject[]>;

// subject entity
@ManyToMany(() => Note, note => note.subjects)
@JoinTable()
notes: Promise<Note[]>;

Avec ces relations paresseuses, vous devrez await pour que les notes liées se chargent avant chaque utilisation, mais vous n'aurez pas besoin de fournir un tableau de relations à la méthode find.

const note = await noteRepo.find({
    where: { id: someId }
});
const subjects = await note.subjects
20
Clément Prévost