【问题标题】:How to update fields of an Entitiy partially (Nest.js ,typescript, typeorm, postgres, sql)如何部分更新实体的字段(Next.js、typescript、typeorm、postgresql)
【发布时间】:2022-08-23 16:04:44
【问题描述】:
async updateOne(
    customerId: string,
    name: string,
    legalStatus: LegalStatus,
    legalRegistrationDate: Date,
    address: string,
    city: City,
    businessPhone: string,
    businessEmail: string,
    businessWebsite: string,
    businessType: BusinessType,
    activityStartingDate: Date,
    fullTimeEmployees: number,
    partTimeEmployees: number,
    yearlyTurnover: number,
    otherInfo: string
  ) {
    const customer = await this.customersRepository.findOne(customerId);

    if (!customer) {
      throw new HttpException(\'Failed to find the Customer with given id\', HttpStatus.NOT_FOUND);
    }

    if (name) {
      const { id } = customer;
      const { name } = customer;

      const customers = await this.customersRepository.find({
        where: {
          id: Not(id),
          name,
        },
      });

      if (customers.length > 0) {
        throw new HttpException(
          \'The Customer with the given name already exists\',
          HttpStatus.BAD_REQUEST
        );
      }
    }

    const payload = {
      name,
      legalStatus,
      legalRegistrationDate,
      address,
      city,
      businessPhone,
      businessEmail,
      businessWebsite,
      businessType,
      activityStartingDate,
      fullTimeEmployees,
      partTimeEmployees,
      yearlyTurnover,
      otherInfo,
    };

    console.log(payload);

    // const updatedCustomer = Object.assign(customer, payload);

    const updatedCustomer = this.customersRepository.update(customer.id, payload);

    if (!updatedCustomer) {
      throw new HttpException(\'Failed to update the Customer\', HttpStatus.INTERNAL_SERVER_ERROR);
    }

    const savedCustomer = this.customersRepository.save(customer);

    if (!savedCustomer) {
      throw new HttpException(\'Failed to save the Customer\', HttpStatus.INTERNAL_SERVER_ERROR);
    }

    return savedCustomer;
  }

我正在使用nest.js、typescript、typeorm、postgress sql。 我想更新实体的特定字段,并且我希望我没有输入的字段不更新。有什么方法可以用来部分而不是全部更新实体。我知道一个方法 Partial< EntityName > 但它不适用于对象作为字段。如果有人能找到它,我想要解决这个问题。

    标签: typescript postgresql nestjs backend crud


    【解决方案1】:

    有一些解决方案。不幸的是,您所描述的更多的是 OOP IMO 的领域。所以让我们把这个问题分解成子问题:

    1. 所以我们可以安全地创建通用更新解决方案,我们需要确保传递的对象确实是给定的类型。我对 ZOD 之类的解决方案没有经验(尽管我正在研究它),所以让我们做一个简单的类来演示这个问题。另外,我不接受 RestController 级别的验证。这真的很麻烦。根据我所知道的 API 设计的最佳实践,Service Layer 是一个实际的 API,Rest Controller 只是一个 PORT。好的,话虽如此,让我们考虑以下接口和类:
      export interface IUser {
          id: number,
          username: string,
          firstName: string
      }
      
      export class User implements IUser {
          id: number;
          username: string;
          firstName: string;
      
          // this is how I prefer doing constructors then:
          constructor(iUser: IUser) {
              this.id = iUser.id;
              this.username = iUser.username;
              this.firstName = iUser.firstName;
              
              // here you can do additional validation using for example class-validator with annotations
          }
      }
      

      到目前为止,一切都很好。那么我们如何确保没有人通过一些恶意字段呢? 我真的很讨厌TS。如果我仍然可以做到,那么强类型语言的意义何在:

      (user as any).password="now your password is gone"
      

      因此,在这种情况下,我所做的就是在我完全控制的代码部分严格执行类型:

      //...some service
      updateUser(user: User) {
          user = user instanceof User ? user : new User(user)
          //... the rest of the code
      }
      

      这是一些 JS 开发人员认为完全多余的单行代码,但我来自 Java 世界,我无法忍受一个类型在 TS 中真的是一个松散的类型。您可以查看here 了解更多关于接口的信息以及它们的不可靠程度。

      1. 现在我们有了一个合适的类型,我们可以对它做一些假设。我喜欢做的是假设:
      • 如果一个字段为空 -> 它应该为空
      • 如果一个字段未定义 -> 它应该被省略

      使用这种方法,您可以实现一个执行以下操作的函数:

      export abstract class Updatable<T> {
        updatePartial(input: Partial<T>): Partial<Omit<T, "id">> {
          const updateObj = Object.keys(this).reduce(
            (prev, curr) =>
              input[curr] !== undefined ? { ...prev, [curr]: input[curr] } : prev,
            {},
          );
          // just in case
          delete (updateObj as any).id;
          return updateObj;
        }
      }
       
      

      它基本上遍历实体的字段并将它们与给定的输入进行比较。您应该确保输入的名称与实体的名称匹配。

      然后只需创建一个 UserEntity 并使其扩展可更新。

      这个解决方案可能远非理想,但如果你想执行安全的 PATCH 操作,这就是我所知道的。如果您找到更好的解决方案,请告诉我,我很乐意让它变得更好:)

    【讨论】:

      猜你喜欢
      • 2021-06-07
      • 2018-09-10
      • 2020-12-22
      • 1970-01-01
      • 2020-01-03
      • 2019-09-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-27
      相关资源
      最近更新 更多