尝试插入具有嵌套 parent 实体的实体时无法插入列 "Id" 错误
Cannot insert into column "Id" error while trying to insert entity that has a nested parent entity
我的 Mikro-Orm (v3.6.15) 模型(连接到 Postgresql - pg v8.3.0)中有 2 个具有一对多关系的实体:
乌古拉玛 (Parent)
@Entity({ tableName: "Uygulamalar", collection: "Uygulamalar" })
export class Uygulama {
@PrimaryKey({ fieldName: "Id" })
id!: number;
@Property({ fieldName: "Adi" })
adi!: string;
@Property({ fieldName: "Kod" })
kod!: string;
@Property({ fieldName: "UygulamaSahibi" })
uygulamaSahibi!: string;
@Property({ fieldName: "createdAt" })
createdAt = new Date();
@Property({ fieldName: "updatedAt", onUpdate: () => new Date() })
updatedAt = new Date();
@OneToMany({ entity: () => Modul, mappedBy: "rootUygulama", cascade: [] })
moduller = new Collection<Modul>(this);
}
模数 (Child)
export class Modul {
@PrimaryKey({ fieldName: "Id" })
id!: number;
@Property({ fieldName: "Adi" })
adi!: string;
@Property({ fieldName: "Kod" })
kod!: string;
@Property({ fieldName: "createdAt" })
createdAt = new Date();
@Property({ fieldName: "updatedAt", onUpdate: () => new Date() })
updatedAt = new Date();
@ManyToOne({ entity: () => Uygulama, joinColumn: "UygulamaId", cascade: [],})
rootUygulama!: Uygulama;
@OneToMany({ entity: () => Ekran, mappedBy: "rootModul", orphanRemoval: true,})
ekranlar = new Collection<Ekran>(this);
}
我有一个休息端点 (Expressjs) 从 posted Http 请求主体创建模块 object :
router.post("/", async (req, res) => {
const modul = DI.modulRepository.create(req.body);
await DI.modulRepository.persistAndFlush(modul);
res.send(modul);
});
当我尝试在下面post JSON object 创建一个新模块时(rootUygulama object 已经在数据库中):
{
"adi": "Deneme Modülü 3",
"kod": "DM1",
"rootUygulama": {
"id": 66,
"adi": "Deneme Uygulaması",
"kod": "DU",
"uygulamaSahibi": "xxxxxx",
"createdAt": "2020-07-24T21:18:47.874Z",
"updatedAt": "2020-07-24T21:18:47.874Z",
"moduller": [
]
}
}
我收到错误:
[query] insert into "Uygulamalar" ("Adi", "Id", "Kod", "UygulamaSahibi", "createdAt", "updatedAt") values ('Deneme Uygulaması', 66, 'DU', 'szengin', '2020-07-25 00:18:47.874', '2020-07-25 00:18:47.874') returning "Id" [took 6 ms]
node_modules/mikro-orm/dist/utils/Logger.js:22
[query] rollback
node_modules/mikro-orm/dist/utils/Logger.js:22
(node:14344) UnhandledPromiseRejectionWarning: error: insert into "Uygulamalar" ("Adi", "Id", "Kod", "UygulamaSahibi", "createdAt", "updatedAt") values (, , , , , ) returning "Id" - cannot insert into column "Id"
at Parser.parseErrorMessage (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\parser.js:278:15)
at Parser.handlePacket (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\parser.js:126:29)
at Parser.parse (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\parser.js:39:38)
at Socket.<anonymous> (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\index.js:8:42)
at Socket.emit (events.js:311:20)
at Socket.EventEmitter.emit (domain.js:482:12)
at addChunk (_stream_readable.js:294:12)
at readableAddChunk (_stream_readable.js:275:11)
at Socket.Readable.push (_stream_readable.js:209:10)
at TCP.onStreamRead (internal/stream_base_commons.js:186:23)
<node_internals>/internal/process/warning.js:32
(node:14344) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
<node_internals>/internal/process/warning.js:32
(node:14344) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
当我如下发送 JSON 时 object 成功创建并插入到数据库中
{
"adi": "Deneme Modülü 3",
"kod": "DM1",
"rootUygulama": 66
}
即使我将空级联数组设置为关系属性存储库也会尝试插入 parent object 但失败了。
我是不是在配置中遗漏了什么?
编辑:
对于我的 Typescript 客户端,我将如何定义 rootUygulama 属性?
export interface Modul {
id: number;
adi: string;
kod: string;
createdAt: Date;
updatedAt: Date;
rootUygulama: Uygulama;
ekranlar: Array<Ekran>;
}
是不是应该这样
rootUygulama: Uygulama | number;
这与级联无关,行为是正确的。当你只传递 PK 时,它被认为是现有实体,如果你传递一个对象,它被认为是新实体。这与是否设置 PK 无关,如果你想要这种行为,你需要自己编程。
MikroORM 基于变更集跟踪工作,因此只有托管对象(从数据库加载的实体)可以生成更新查询。如果要为 rootUygulama
对象触发更新查询,请使用 em.nativeUpdate()
。如果您仍想将负载作为对象发送,但您只关心 PK,您还可以将该实体显式合并到 EM(这样它就变成托管的,就像您从数据库加载它一样)。
const modul = DI.modulRepository.create(req.body);
// if we see PK, we merge, so it won't be considered as new object
if (modul.rootUygulama.id) {
DI.em.merge(modul.rootUygulama);
// here we could also fire the `em.nativeUpdate(Uygulama, modul.rootUygulama);`
// to fire an update query, but then you should use `em.transactional()` to have that update query inside the same TX as the flush
}
await DI.modulRepository.persistAndFlush(modul);
res.send(modul);
顺便说一句,我强烈建议您不要禁用级联,除非您真正了解自己在做什么,因为默认设置是级联合并和持久化,您通常 want/need。
我的 Mikro-Orm (v3.6.15) 模型(连接到 Postgresql - pg v8.3.0)中有 2 个具有一对多关系的实体:
乌古拉玛 (Parent)
@Entity({ tableName: "Uygulamalar", collection: "Uygulamalar" })
export class Uygulama {
@PrimaryKey({ fieldName: "Id" })
id!: number;
@Property({ fieldName: "Adi" })
adi!: string;
@Property({ fieldName: "Kod" })
kod!: string;
@Property({ fieldName: "UygulamaSahibi" })
uygulamaSahibi!: string;
@Property({ fieldName: "createdAt" })
createdAt = new Date();
@Property({ fieldName: "updatedAt", onUpdate: () => new Date() })
updatedAt = new Date();
@OneToMany({ entity: () => Modul, mappedBy: "rootUygulama", cascade: [] })
moduller = new Collection<Modul>(this);
}
模数 (Child)
export class Modul {
@PrimaryKey({ fieldName: "Id" })
id!: number;
@Property({ fieldName: "Adi" })
adi!: string;
@Property({ fieldName: "Kod" })
kod!: string;
@Property({ fieldName: "createdAt" })
createdAt = new Date();
@Property({ fieldName: "updatedAt", onUpdate: () => new Date() })
updatedAt = new Date();
@ManyToOne({ entity: () => Uygulama, joinColumn: "UygulamaId", cascade: [],})
rootUygulama!: Uygulama;
@OneToMany({ entity: () => Ekran, mappedBy: "rootModul", orphanRemoval: true,})
ekranlar = new Collection<Ekran>(this);
}
我有一个休息端点 (Expressjs) 从 posted Http 请求主体创建模块 object :
router.post("/", async (req, res) => {
const modul = DI.modulRepository.create(req.body);
await DI.modulRepository.persistAndFlush(modul);
res.send(modul);
});
当我尝试在下面post JSON object 创建一个新模块时(rootUygulama object 已经在数据库中):
{
"adi": "Deneme Modülü 3",
"kod": "DM1",
"rootUygulama": {
"id": 66,
"adi": "Deneme Uygulaması",
"kod": "DU",
"uygulamaSahibi": "xxxxxx",
"createdAt": "2020-07-24T21:18:47.874Z",
"updatedAt": "2020-07-24T21:18:47.874Z",
"moduller": [
]
}
}
我收到错误:
[query] insert into "Uygulamalar" ("Adi", "Id", "Kod", "UygulamaSahibi", "createdAt", "updatedAt") values ('Deneme Uygulaması', 66, 'DU', 'szengin', '2020-07-25 00:18:47.874', '2020-07-25 00:18:47.874') returning "Id" [took 6 ms]
node_modules/mikro-orm/dist/utils/Logger.js:22
[query] rollback
node_modules/mikro-orm/dist/utils/Logger.js:22
(node:14344) UnhandledPromiseRejectionWarning: error: insert into "Uygulamalar" ("Adi", "Id", "Kod", "UygulamaSahibi", "createdAt", "updatedAt") values (, , , , , ) returning "Id" - cannot insert into column "Id"
at Parser.parseErrorMessage (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\parser.js:278:15)
at Parser.handlePacket (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\parser.js:126:29)
at Parser.parse (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\parser.js:39:38)
at Socket.<anonymous> (d:\NODEJS\BildirimYonetimi\backend\node_modules\pg-protocol\dist\index.js:8:42)
at Socket.emit (events.js:311:20)
at Socket.EventEmitter.emit (domain.js:482:12)
at addChunk (_stream_readable.js:294:12)
at readableAddChunk (_stream_readable.js:275:11)
at Socket.Readable.push (_stream_readable.js:209:10)
at TCP.onStreamRead (internal/stream_base_commons.js:186:23)
<node_internals>/internal/process/warning.js:32
(node:14344) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
<node_internals>/internal/process/warning.js:32
(node:14344) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
当我如下发送 JSON 时 object 成功创建并插入到数据库中
{
"adi": "Deneme Modülü 3",
"kod": "DM1",
"rootUygulama": 66
}
即使我将空级联数组设置为关系属性存储库也会尝试插入 parent object 但失败了。
我是不是在配置中遗漏了什么?
编辑:
对于我的 Typescript 客户端,我将如何定义 rootUygulama 属性?
export interface Modul {
id: number;
adi: string;
kod: string;
createdAt: Date;
updatedAt: Date;
rootUygulama: Uygulama;
ekranlar: Array<Ekran>;
}
是不是应该这样
rootUygulama: Uygulama | number;
这与级联无关,行为是正确的。当你只传递 PK 时,它被认为是现有实体,如果你传递一个对象,它被认为是新实体。这与是否设置 PK 无关,如果你想要这种行为,你需要自己编程。
MikroORM 基于变更集跟踪工作,因此只有托管对象(从数据库加载的实体)可以生成更新查询。如果要为 rootUygulama
对象触发更新查询,请使用 em.nativeUpdate()
。如果您仍想将负载作为对象发送,但您只关心 PK,您还可以将该实体显式合并到 EM(这样它就变成托管的,就像您从数据库加载它一样)。
const modul = DI.modulRepository.create(req.body);
// if we see PK, we merge, so it won't be considered as new object
if (modul.rootUygulama.id) {
DI.em.merge(modul.rootUygulama);
// here we could also fire the `em.nativeUpdate(Uygulama, modul.rootUygulama);`
// to fire an update query, but then you should use `em.transactional()` to have that update query inside the same TX as the flush
}
await DI.modulRepository.persistAndFlush(modul);
res.send(modul);
顺便说一句,我强烈建议您不要禁用级联,除非您真正了解自己在做什么,因为默认设置是级联合并和持久化,您通常 want/need。