【问题标题】:Select attributes on repository.find() with relations (TypeORM)使用关系(TypeORM)选择 repository.find() 上的属性
【发布时间】:2021-09-30 12:24:22
【问题描述】:

我的方法返回一个包含所有用户对象的账单对象。 我希望我只返回具有实体中两个属性的账单对象和用户。我使用 TypeORM

  /**
   * Returns a bills by account bill
   */
  async getByAccountBill(
    accountBill: string,
    id?: number
  ): Promise<Object | undefined> {
    const userService = new UserService();
    const user = await userService.getById(id);

    const bills = await this.billRepository.find({
      select: ["accountBill"],
      where: {
        accountBill: Like(`${accountBill}%`),
        user: Not(`${user.id}`)
      },
      relations: ["user"] // I get All object Entity (userId, password, login...) I want to only name and surname
    });

    if (bills) {
      return bills;
    } else {
      return undefined;
    }
  }

【问题讨论】:

    标签: javascript typescript typeorm


    【解决方案1】:

    您可以使用 TypeOrm 最强大的工具之一 querybuilder 来执行此操作。

    const values = this.billRepository.createQueryBuilder("bill")
        .leftJoinAndSelect("bill.user", "user")
        .where("bill.accountBill LIKE :accountBill", {accountBill})
        .andWhere("user.id = :userId", {userId: user.id})
        .select(["user.name", "user.surname"])
        .execute();
    
    // NOTE
    // .execute() will return raw results.
    // To return objects, use .getMany()
    

    【讨论】:

    • 'execute' 方法返回一个原始结果,所以也许你最好使用 getMany 来返回一个对象
    • 嘿@zenbeni,我正在尝试做类似的事情,但如果没有用户并且andWhere 条件失败,它将返回undefined。如果关系表中还没有条目,我们如何使相同的查询工作?
    • 该问题明确提到了 find() 方法。我们希望依靠我们已经在模型中完成的布线。查询构建器是一个强大的工具,但它应该只用于在我看来模型连接不够的复杂查询中。问题包括一个简单的查询。
    • @hadaytullah 你不能使用基本的模型接线,因为在 User 中只有 2 个字段完全超出了包含更多字段的 vanilla 模型。您必须使用自定义查询到对象映射才能这样做。因此,查询生成器,这对我来说是正确的工具。
    • 数据是性能所在,您提出的解决方案意味着更多的网络使用,当您获取比您需要的更多数据时,数据库上的 I/O 更多(I/O 和网络在大多数情况下更多比任何内存算法优化都重要)。此外,您还添加了数据结构和 TypeOrm 的非原始用法以及之后必须维护的自定义代码(与经典的 querybuilder api 用法相反)。在数据库上显式获取列数据后删除它们充其量是次优的,应该避免在性能方面。
    【解决方案2】:

    有点晚了,但对于所有访问此页面的其他人可能会有所帮助 typeorm 中提供了一个选项,因此我们可以得到我们想要的结果。

    【讨论】:

      【解决方案3】:

      如果有人感兴趣,请列出与关系相关的代码和回购链接...

      https://github.com/typeorm/typeorm/blob/master/src/find-options/FindOptionsUtils.ts

          /**
           * Applies give find options to the given query builder.
           */
          static applyOptionsToQueryBuilder<T>(qb: SelectQueryBuilder<T>, options: FindOneOptions<T> | FindManyOptions<T> | undefined): SelectQueryBuilder<T>;
      ...
              if (options.loadRelationIds === true) {
                  qb.loadAllRelationIds();
              }
              else if (options.loadRelationIds instanceof Object) {
                  qb.loadAllRelationIds(options.loadRelationIds);
              }
      

      https://github.com/typeorm/typeorm/blob/master/src/query-builder/SelectQueryBuilder.ts

      /**
       * Loads all relation ids for all relations of the selected entity.
       * All relation ids will be mapped to relation property themself.
       * If array of strings is given then loads only relation ids of the given properties.
       */
      loadAllRelationIds(options?: { relations?: string[], disableMixedMap?: boolean }): this { // todo: add skip relations
          this.expressionMap.mainAlias!.metadata.relations.forEach(relation => {
              if (options !== undefined && options.relations !== undefined && options.relations.indexOf(relation.propertyPath) === -1)
                  return;
      
              this.loadRelationIdAndMap(
                  this.expressionMap.mainAlias!.name + "." + relation.propertyPath,
                  this.expressionMap.mainAlias!.name + "." + relation.propertyPath,
                  options
              );
          });
          return this;
      }
      
      /**
       * LEFT JOINs relation id and maps it into some entity's property.
       * Optionally, you can add condition and parameters used in condition.
       */
      loadRelationIdAndMap(mapToProperty: string, relationName: string, options?: { disableMixedMap?: boolean }): this;
      
      /**
       * LEFT JOINs relation id and maps it into some entity's property.
       * Optionally, you can add condition and parameters used in condition.
       */
      loadRelationIdAndMap(mapToProperty: string, relationName: string, alias: string, queryBuilderFactory: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>): this;
      
      /**
       * LEFT JOINs relation id and maps it into some entity's property.
       * Optionally, you can add condition and parameters used in condition.
       */
      loadRelationIdAndMap(mapToProperty: string,
                           relationName: string,
                           aliasNameOrOptions?: string|{ disableMixedMap?: boolean },
                           queryBuilderFactory?: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>): this {
      
          const relationIdAttribute = new RelationIdAttribute(this.expressionMap);
          relationIdAttribute.mapToProperty = mapToProperty;
          relationIdAttribute.relationName = relationName;
          if (typeof aliasNameOrOptions === "string")
              relationIdAttribute.alias = aliasNameOrOptions;
          if (aliasNameOrOptions instanceof Object && (aliasNameOrOptions as any).disableMixedMap)
              relationIdAttribute.disableMixedMap = true;
      
          relationIdAttribute.queryBuilderFactory = queryBuilderFactory;
          this.expressionMap.relationIdAttributes.push(relationIdAttribute);
      
          if (relationIdAttribute.relation.junctionEntityMetadata) {
              this.expressionMap.createAlias({
                  type: "other",
                  name: relationIdAttribute.junctionAlias,
                  metadata: relationIdAttribute.relation.junctionEntityMetadata
              });
          }
          return this;
      }
      

      https://github.com/typeorm/typeorm/blob/master/src/query-builder/relation-id/RelationIdAttribute.ts

      /**
       * Stores all join relation id attributes which will be used to build a JOIN query.
       */
      export class RelationIdAttribute {
      
          // -------------------------------------------------------------------------
          // Public Properties
          // -------------------------------------------------------------------------
      
          /**
           * Alias of the joined (destination) table.
           */
          alias?: string;
      
          /**
           * Name of relation.
           */
          relationName: string;
      
          /**
           * Property + alias of the object where to joined data should be mapped.
           */
          mapToProperty: string;
      
          /**
           * Extra condition applied to "ON" section of join.
           */
          queryBuilderFactory?: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>;
      
          /**
           * Indicates if relation id should NOT be loaded as id map.
           */
          disableMixedMap = false;
      ...
      

      【讨论】:

        猜你喜欢
        • 2020-06-30
        • 1970-01-01
        • 2021-01-14
        • 2019-06-14
        • 1970-01-01
        • 2022-07-12
        • 2019-12-30
        • 2021-02-08
        • 2022-07-16
        相关资源
        最近更新 更多