【问题标题】:TypeORM - duplicate key value violationTypeORM - 重复键值违规
【发布时间】:2021-09-03 07:40:11
【问题描述】:

假设我有一个像这样的简单 TypeORM 实体:

import { Entity, PrimaryGeneratorColumn, Column } from 'typeorm';

@Entity()
export class Employee {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    Name: string;
}

只要我不手动触摸数据库,一切都可以正常工作。如果我手动输入一条记录,实体将无法检查表中最后一个当前的id,并抛出错误duplicate key value violates unique constraint

例如:

  1. Employee Entity 自己创建两条记录。
  2. 我的数据库中有两条记录,最后一条记录有id 2
  3. 我在数据库中手动创建了第三条记录,它有id 3
  4. 之后,当 Employee Entity 运行时,它不会 = 创建另一条记录,因为它想使用 id 3,但我已经手动添加了。
  5. 我收到错误duplicate key value violates unique constraint
  6. Employee Entity 再次运行时,它会工作,因为它会尝试在id 4 下保存另一条已经可用的记录。

那么我如何确保 Employee Entity 检查数据库中的最后一个 id,然后使用增量 id 保存下一条记录?

谢谢

【问题讨论】:

  • 你能把你的id从增量(数字)改成uuid吗? PS:出于安全原因,建议使用伪随机 id 而不是简单的增量。
  • 嗨@CarloCorradini,谢谢你的建议。如果无论如何使用伪随机ID更好,那么我可以这样做。
  • 不错!记住:@PrimaryGeneratedColumn('uuid')

标签: orm nestjs typeorm


【解决方案1】:

就我而言,我错误地定义了关系。它应该是@ManyToOne,但我有@OneToOne。 这是有道理的,因为 OneToOne 应该为每个实体有一个实例,因此序列生成器为每个尝试的插入提供相同的 id,导致错误,因为它对于后续保存不是唯一的。我认为 TypeORM 应该给出不同的错误信息,我花了 2 天时间才弄清楚。

【讨论】:

    【解决方案2】:

    在 TypeORM 中,装饰器 @PrimaryGeneratedColumn() 创建一个主列,其值将使用序列生成。每次在数据库中添加新记录时,它都会使用为该列设置的序列的nextval。假设您使用的是 PostgreSQL(我相信对于其他数据库它会类似),您有一个 Employee 表

    CREATE TABLE public.Employee (
        number serial NOT NULL,
        nane varchar NULL
    );
    

    因为装饰器@PrimaryGeneratedColumn() 也会创建一个序列employee_id_seq。您可以通过运行检查其最新值

    select last_value from employee_id_seq; 
    

    当您的应用程序创建两条记录时,它会使用该序列生成新的 ID,从而更改 employee_id_seq last_value 值。数据库中有两条记录,新的 last_value 将更新为 2。

    如果您通过 id = 3 手动创建第三条记录

    INSERT INTO public.Employee (id, name) VALUES(3, 'new_name')
    

    不会使用序列,它的 last_value 将为 2。下次您的应用程序尝试插入新记录时,它会在不传递 id 的情况下执行插入,因为它依赖于序列来生成值,就像这样

    INSERT INTO public.Employee (name) VALUES('another_name');
    

    或者(不确定 TypeORM 是如何准确处理的)

    INSERT INTO public.Employee (id, name) VALUES(nextval('employee_id_seq', 'another_name')
    

    上面的 SQL 将使用序列中的 last_value 并加 1,得到 3 和 duplicate key violation。因此,如果您手动添加记录,则不需要手动设置 id,您可以运行

    INSERT INTO public.Employee (name) VALUES('name') 
    

    id 将使用序列自动生成。

    【讨论】:

    • 感谢 V. Lovato 的精彩解释,它真的帮助了我!现在我知道它在幕后是如何运作的。
    猜你喜欢
    • 2022-11-04
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2015-04-20
    相关资源
    最近更新 更多