TypeORM 保存嵌套对象
Posted
技术标签:
【中文标题】TypeORM 保存嵌套对象【英文标题】:TypeORM save nested objects 【发布时间】:2021-07-26 14:13:33 【问题描述】:我正在开发一个 express(使用 TypeORM)+ ReactJS 应用程序。
问题是我有 3 个通过 OneToMany 关系链接的实体,如下所示:
-
客户
产品(链接到客户)
型号(链接到产品)
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|
如何在不发送数据库中所有现有模型的情况下添加新模型并更新现有模型?
【问题讨论】:
【参考方案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
【讨论】:
以上是关于TypeORM 保存嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章
NestJS + Typeorm + Graphql:嵌套关系中 DTO 的正确设计模式