【问题标题】:TypeORM save nested objectsTypeORM 保存嵌套对象
【发布时间】:2021-07-26 14:13:33
【问题描述】:

我正在开发一个 express(使用 TypeORM)+ ReactJS 应用程序。

问题是我有 3 个通过 OneToMany 关系链接的实体,如下所示:

  1. 客户
  2. 产品(链接到客户)
  3. 型号(链接到产品)
import { Product } from './product.entity'

@Entity('customer')
export class Customer extends BaseEntity{
    @PrimaryGeneratedColumn()
    readonly id: number;
   
    @Column ({name: 'name'})
    name : string;

    @Column ({name: 'test', nullable: true})
    test : string;

    @OneToMany(() => Product, product => product.customer)
    // @JoinColumn({ name: 'product_id' })
    products: Product[]
}
import {Customer} from './customer.entity'
import {Model} from './model.entity'

@Entity('product')
export class Product extends BaseEntity{
    @PrimaryGeneratedColumn()
    readonly id: number;
   
    @Column ({name: 'name'})
    name : string;

    @Column ({name: 'test', nullable: true})
    test : string;

    @Column ({name: 'deleted', nullable: true})
    deleted : string;
    
    @ManyToOne(() => Customer, customer => customer.products)
    @JoinColumn({ name: 'customer_id' })
    customer: Customer;

    @OneToMany(() => Model, model => model.product)
    @JoinColumn({ name: 'customer_id' })
    models: Model[]
}
import { Product } from "./product.entity";

@Entity('model')
export class Model extends BaseEntity{
    @PrimaryGeneratedColumn()
    readonly id: number;
   
    @Column ({name: 'name'})
    name : string;

    @Column ({name: 'size', nullable: true})
    size : string;

    @Column ({name: 'deleted', nullable: true})
    deleted : string;
    
    @ManyToOne(() => Product, product => product.models)
    @JoinColumn({ name: 'product_id' })
    product: Product;
}

Express 的保存方法是:

  static add = async(req: Request, res)=> {
    const connection = getConnection();
    const queryRunner = connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      let customer: Customer
      customer = await queryRunner.manager.getRepository(Customer).findOneOrFail(req.body.id)

      const productsReq: Array<Product> = req.body.products
      productsReq.forEach(async (product: any) => {
        let updatedProd =  {...product, customer: customer}
        const savedProd = await queryRunner.manager.getRepository(Product).save({...updatedProd})
        product.models.forEach(async (model: any) => {
          let updatedModel = {...model, product: savedProd}
          await queryRunner.manager.getRepository(Model).save(updatedModel)
        });
      });

      await queryRunner.commitTransaction();
      return res.send('Saving done')

    } catch (error) {
      console.log(error)
      await queryRunner.rollbackTransaction();
      res.status(500).send('Some error occurs');
    } finally {
    }
  }

目前,在数据库中,我有以下数据:

1 个 ID 为 30 的客户

name id test
first customer 30 test column

1 个 ID 为 119 的产品与客户 30 相关联

id name test customer_id deleted
119 first product test column 30

ID 为 90 和 91 的 2 个模型链接到产品 119

id name size deleted product_id
91 second model witout id 2000 119
90 first model with id 1000 119

接下来,在 React 中,我尝试仅更新 id 为 90 的模型并添加一个新模型。 (所以我没有将所有模型发送到后端,没有发送 id 91 的模型)。

从前端发送到后端的 JSON 对象如下所示:

{
    "id": 30,
    "name": "first customer",
    "test": "test column",
    "products": [
        {
            "id" : 119,   
            "name": "first product",
            "test": "test column",
            "models": [
                {
                    "id": 90,
                    "name": "first model with id",
                    "size": 1000
                },
                {
                    "name": "second model witout id",
                    "size": 2000
                }
            ]
        }

    ]
}

但问题是在 DB 中,表“model”上的外键“product_id”对于 id 为 91 的模型设置为 null,并插入了一个新行 (92)。

结果是:

|id|name|size|deleted|product_id|
|--|----|----|-------|----------|
|91|second model witout id|2000|||
|90|first model with id|1000||119|
|92|second model witout id|2000||119|

如何在不发送数据库中所有现有模型的情况下添加新模型并更新现有模型?

【问题讨论】:

    标签: json one-to-many typeorm many-to-one nested-object


    【解决方案1】:

    我想我找到了解决办法。

    我从 Express 中更改了保存方法,如下所示:

      static add = async(req: Request, res)=> {
        const connection = getConnection();
        const queryRunner = connection.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
          let customer: Customer
          let customerReq: any = req.body
          customer = await queryRunner.manager.getRepository(Customer).findOneOrFail(req.body.id)
          const productsReq: Array<Product> = req.body.products
          
          productsReq.forEach(async (product: any) => {
            let updatedProd =  {...product, customer: customer}
            let addedModels: Model[] = []
            product.models.forEach(async (model: any) => {
              const updatedModel = await queryRunner.manager.getRepository(Model).save({...model, product: product})
              addedModels.push(updatedModel)
            });
            const existingProd = await queryRunner.manager.getRepository(Product).save({...updatedProd})
            await (await existingProd.models).push(...addedModels)
            const savedProd = await queryRunner.manager.getRepository(Product).save({...updatedProd})
          });
    
          await queryRunner.commitTransaction();
          return res.send('Adding ok')
    
        } catch (error) {
          console.log(error)
          await queryRunner.rollbackTransaction();
          res.status(500).send('Something went terribly wrong');
        } finally {
          console.log('release')
          // await queryRunner.release();
        }
      }
    

    这很奇怪,因为启动了 2 个事务:

    query: START TRANSACTION
    query: SELECT "Customer"."id" AS "Customer_id", "Customer"."name" AS "Customer_name", "Customer"."test" AS "Customer_test" FROM "customer" "Customer" WHERE "Customer"."id" IN ($1) -- PARAMETERS: [30]
    query: SELECT "Customer"."id" AS "Customer_id", "Customer"."name" AS "Customer_name", "Customer"."test" AS "Customer_test" FROM "customer" "Customer" WHERE "Customer"."id" IN ($1) -- PARAMETERS: [30]
    query: COMMIT
    query: SELECT "Model"."id" AS "Model_id", "Model"."name" AS "Model_name", "Model"."size" AS "Model_size", "Model"."deleted" AS "Model_deleted", "Model"."product_id" AS "Model_product_id" FROM "model" "Model" WHERE "Model"."id" IN ($1) -- PARAMETERS: [132]
    query: SELECT "Product"."id" AS "Product_id", "Product"."name" AS "Product_name", "Product"."test" AS "Product_test", "Product"."deleted" AS "Product_deleted", "Product"."customer_id" AS "Product_customer_id" FROM "product" "Product" WHERE "Product"."id" IN ($1) -- PARAMETERS: [119]
    query: INSERT INTO "model"("name", "size", "deleted", "product_id") VALUES ($1, $2, DEFAULT, $3) RETURNING "id" -- PARAMETERS: ["second model witout id",2000,119]
    release
    
     Morgan -->  POST 200 /test @ Tue, 04 May 2021 14:28:08 GMT ::ffff:127.0.0.1 from undefined PostmanRuntime/7.28.0
    
    query: START TRANSACTION
    query: SELECT "Product"."id" AS "Product_id", "Product"."name" AS "Product_name", "Product"."test" AS "Product_test", "Product"."deleted" AS "Product_deleted", "Product"."customer_id" AS "Product_customer_id" FROM "product" "Product" WHERE "Product"."id" IN ($1) -- PARAMETERS: [119]
    query: UPDATE "model" SET "size" = $2 WHERE "id" IN ($1) -- PARAMETERS: [132,8000]
    query: COMMIT
    

    【讨论】:

      猜你喜欢
      • 2012-09-29
      • 2012-10-05
      • 2014-07-26
      • 2017-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-26
      相关资源
      最近更新 更多