Nest.js + Mikro-ORM:使用createQueryBuilder和leftJoin时未初始化的实体集合

时间:2020-04-29 21:53:56

标签: nestjs mikro-orm

我正在使用Nest.js,并考虑从TypeORM迁移到Mikro-ORM。我正在使用nestjs-mikro-orm模块。但是我被困在一个看起来很简单的东西上……

我有3个实体,AuthorEntityBookEntityBookMetadata。在我的Author模块中,我尝试使用Book方法将BookMetadatacreateQueryBuilder表联接在一起。但是运行查询时,在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();
  }
}

我错过了什么吗?可能没有关系,但我也注意到使用Nest.js的TypeORM用户有a special autoLoadEntities: true。 Mikro-ORM有类似的东西吗?谢谢;)

1 个答案:

答案 0 :(得分:1)

尚不支持从单个查询映射多个实体,这已计划用于v4。您可以在此处订阅:https://github.com/mikro-orm/mikro-orm/issues/440

在v3中,您需要使用2个查询来加载2个实体,这对于您的用例而言,没有QB的情况要容易得多。

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

或者您可以使用qb.execute()来获取原始结果并自己映射它们,但是您还必须手动别名所有字段来避免重复(Author.nameBook.name) ,因为进行qb.select(['a.*', 'b.*'])会导致查询select a.*, b.* ...,并且重复的列将无法正确映射。

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

关于autoLoadEntities的事情,从来没有听说过,它将看一下它是如何工作的,但是总的来说,nestjs适配器不是我开发的,所以如果它只与嵌套有关,那会更好问他们的GH回购。

或者您可以使用基于文件夹的发现(entitiesDirs)。

这是包含3个实体的新示例:

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

这将产生3个查询,每个db表一个,但是第一个查询将自动联接book和bookMetadata以能够被它们过滤。该条件将在第二和第三查询中向下传播。

如果您省略填充参数(['books.bookMetadata']),则仅会触发第一个查询,并且最终会导致书籍没有填充(但将向作者查询合并条件)。