0

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

我有 3 个实体AuthorEntityBookEntityBookMetadata。在我的Author模块中,我尝试使用该方法左连接BookBookMetadatacreateQueryBuilder。但是在运行我的查询时,我收到一个错误 where 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 用户有一个特殊之处。autoLoadEntities: trueMikro-ORM 有类似的东西吗?谢谢 ;)

4

1 回答 1

1

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

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

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

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

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

关于这autoLoadEntities件事,从来没有听说过,会看看它是如何工作的,但总的来说,nestjs 适配器不是我开发的,所以如果它只是与嵌套相关的东西,最好在他们的 GH repo 上询问。

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

这是具有 3 个实体的新示例:

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

这将产生 3 个查询,每个 db 表一个,但第一个将自动连接书籍和 bookMetadata 以便能够通过它们进行过滤。该条件将在第二个和第三个查询中向下传播。

如果省略填充参数 ( ['books.bookMetadata']),则只会触发第一个查询,并且最终会得到未填充的书籍(但将使用连接条件查询作者)。

于 2020-04-29T22:21:07.137 回答