【问题标题】:QueryFailedError: insert or update on table "graph" violates foreign key constraint "FK_0e40......"QueryFailedError:在表“graph”上插入或更新违反了外键约束“FK_0e40......”
【发布时间】:2020-06-28 19:11:00
【问题描述】:

我创建了一个非常小的reproduction repository

请在下面查看我可能的解决方法。


我有一个图和一个图节点实体。图只知道它的起始图节点,而节点本身知道它属于哪个图及其后继图。

@Entity()
export class Graph extends BaseEntity {
  @PrimaryGeneratedColumn("uuid")
  public id: string;

  @Column({ nullable: true })
  public startNodeId?: string;

  @ManyToOne(() => GraphNode)
  @JoinColumn({ name: "startNodeId" })
  public startNode?: GraphNode;
}

@Entity()
export class GraphNode extends BaseEntity {
  @PrimaryGeneratedColumn("uuid")
  public id: string;

  @PrimaryColumn("uuid")
  public graphId: string;

  @ManyToOne(() => Graph, { onDelete: "CASCADE" })
  @JoinColumn({ name: "graphId" })
  public graph: Graph;

  @Column({ nullable: true })
  public successorGraphNodeId?: string;

  @ManyToOne(() => GraphNode)
  @JoinColumn({ name: "successorGraphNodeId" })
  public successorGraphNode?: GraphNode;
}

如您所见,图表的 startnode 可能为空。此外,图形节点可能没有后继节点,因此该字段也可能为空。图节点具有复合主键很重要,因为它始终属于一个图。

我创建了一些非常基本的 CRUD 存储库操作来创建图形和图形节点。稍后我想更新该图的起始节点 ID。

图节点存储库只是创建了一个新实体

  public createGraphNode(graphId: string, successorGraphNodeId?: string): Promise<GraphNode> {
    const graphNode: GraphNode = new GraphNode();
    graphNode.graphId = graphId;
    graphNode.successorGraphNodeId = successorGraphNodeId;
    return graphNode.save();
  }

图形存储库创建一个新实体并能够更新其起始节点 ID

  public createGraph(startNodeId?: string): Promise<Graph> {
    const graph: Graph = new Graph();
    graph.startNodeId = startNodeId;
    return graph.save();
  }

  public updateStartNodeId(graphId: string, startNodeId: string): Promise<UpdateResult> {
    return this.update(graphId, {
      startNodeId
    });
  }

在运行应用程序时,我会创建一个新图表。之后,我创建一个新的图形节点并将图形 ID 分配给它。此图节点没有后继节点。最后我将图节点指定为图开始节点。

const graph: Graph = await graphsRepository.createGraph();
const graphNode: GraphNode = await graphNodesRepository.createGraphNode(graph.id);
await graphsRepository.updateStartNodeId(graph.id, graphNode.id);

这样做我得到以下数据库错误

QueryFailedError: 在表“graph”上插入或更新违反了外部 关键约束“FK_0e4022833a9efc062c01637e552”

看来我的实体设计是错误的。有人知道怎么解决吗?

提前致谢


我可能会解决它

图形实体

通过referencedColumnName: "id"创建对PK的引用

@ManyToOne(() => GraphNode)
@JoinColumn({ name: "startNodeId", referencedColumnName: "id" })
public startNode?: GraphNode;

图节点实体

对后继图节点执行相同操作

@ManyToOne(() => GraphNode)
@JoinColumn({ name: "successorGraphNodeId", referencedColumnName: "id" })
public successorGraphNode?: GraphNode;

还将Unique 装饰器添加到实体并将id 字段标记为唯一

@Unique(["id"])

我唯一的问题是我不知道为什么要这样解决。

  • 不知道为什么要通过referencedColumnName: "id"引用被引用表的PK,这个应该很明显了
  • 我也不知道为什么我必须通过@Unique(["id"]) 将 id 列标记为唯一,因为该字段将始终是唯一的

【问题讨论】:

  • 您是否尝试在 @OneToMany 属性中同时设置 { onDelete: "CASCADE" } 和 {cascade: ["insert", "update", "remove" ]}?
  • @Aurinxki 这会有所作为吗?我专注于我在修复解决方案中提出的问题:)

标签: postgresql nestjs typeorm


【解决方案1】:

在您的 .Save() 中将 id 作为参数传递,否则它会认为您正在创建新数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-27
    • 2020-12-02
    • 1970-01-01
    • 2015-08-19
    • 2020-09-07
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多