Гнездо. js + Mikro-ORM: Коллекция сущностей, не инициализированных при использовании createQueryBuilder и leftJoin - PullRequest
0 голосов
/ 30 апреля 2020

Я использую Nest. js и собираюсь перейти с TypeORM на Mikro-ORM. Я использую модуль nestjs-mikro-orm. Но я застрял на чем-то, что кажется очень простым ...

У меня есть 3 сущности, AuthorEntity, BookEntity и BookMetadata. Из моего модуля Author я пытаюсь соединить таблицы Book и BookMetadata слева с помощью метода createQueryBuilder. Но при выполнении моего запроса я получаю сообщение об ошибке Collection<BookEntity> of entity AuthorEntity[3390] not initialized. Однако столбцы из таблицы Author хорошо извлекаются.

Мои 3 объекта:

@Entity()
@Unique({ properties: ['key'] })
export class AuthorEntity {
  @PrimaryKey()
  id!: number;

  @Property({ length: 255 })
  key!: string;

  @OneToMany('BookEntity', 'author', { orphanRemoval: true })
  books? = new Collection<BookEntity>(this);
}

@Entity()
export class BookEntity {
  @PrimaryKey()
  id!: number;

  @ManyToOne(() => AuthorEntity)
  author!: AuthorEntity;

  @OneToMany('BookMetadataEntity', 'book', { orphanRemoval: true })
  bookMetadata? = new Collection<BookMetadataEntity>(this);
}

@Entity()
@Unique({ properties: ['book', 'localeKey'] })
export class BookMetadataEntity {
  @PrimaryKey()
  id!: number;

  @Property({ length: 5 })
  localeKey!: string;

  @ManyToOne(() => BookEntity)
  book!: BookEntity;
}

И служебный файл, в котором я выполняю свой запрос:

@Injectable()
export class AuthorService {
  constructor(
    @InjectRepository(AuthorEntity)
    private readonly authorRepository: EntityRepository<AuthorEntity>,
  ) {}

  async findOneByKey(props: { key: string; localeKey: string; }): Promise<AuthorEntity> {
    const { key, localeKey } = props;

    return this.authorRepository
      .createQueryBuilder('a')
      .select(['a.*', 'b.*', 'c.*'])
      .leftJoin('a.books', 'b')
      .leftJoin('b.bookMetadata', 'c')
      .where('a.key = ?', [key])
      .andWhere('c.localeKey = ?', [localeKey])
      .getSingleResult();
  }
}

Я что-то пропустил? Возможно, это не связано, но я также заметил, что специальный autoLoadEntities: true для пользователей TypeORM, использующих Nest. js. Есть ли что-то похожее для Микро-ОРМ? Спасибо;)

1 Ответ

1 голос
/ 30 апреля 2020

Отображение нескольких сущностей из одного запроса пока не поддерживается, планируется для v4. Вы можете подписаться здесь: https://github.com/mikro-orm/mikro-orm/issues/440

В v3 вам нужно использовать 2 запроса для загрузки 2 сущностей, что для вашего варианта использования гораздо проще без участия QB.

return this.authorRepository.findOne({ key }, ['books']);

Или вы можете использовать qb.execute(), чтобы получить необработанные результаты и отобразить их самостоятельно, но вам также придется вручную псевдоним всех полей, чтобы обойти дубликаты (Author.name против Book.name) , так как выполнение qb.select(['a.*', 'b.*']) приведет к запросу select a.*, b.* ..., и дублированные столбцы не будут правильно отображены.

https://mikro-orm.io/docs/query-builder/#mapping -raw-results-to-entity

Об элементе autoLoadEntities, о котором никогда не слышали, рассмотрим, как он работает, но в общем, адаптер nest js не разработан мной, поэтому, если это что-то, связанное только с гнездом, было бы лучше спросить об их репозитории GH.

Или вы можете использовать обнаружение на основе папок (entitiesDirs).

вот новый пример с 3 сущностями:

return this.authorRepository.findOne({ 
  key,
  books: { bookMetadata: localeKey } },
}, ['books.bookMetadata']);

Это даст 3 запроса, по одному для каждой таблицы БД, но первый будет автоматически присоединен книги и bookMetadata, чтобы иметь возможность фильтрации по ним. Условие будет распространено вниз во втором и третьем запросе.

Если вы не укажете параметр заполнения (['books.bookMetadata']), то будет запущен только первый запрос, и в итоге книги не будут заполнены (но автору будет предложено условие объединения).

...