Ограничение внешнего ключа »FK_0e4022833a9efc062c01637e552« не может быть реализовано - проблема с составным первичным ключом? - PullRequest
5 голосов
/ 28 февраля 2020

Я использую TypeORM и хочу создать базу данных с тремя объектами. Я создал репозиторий для воспроизведения

Github Reproduction репозиторий

Обновление

Я смог воспроизвести его только с двумя маленькими лица

Очень маленькое репо-репродукция

подробнее об этом ниже


Итак, прежде всего, у меня есть модуль сущность. Это маленький, потому что он хранит только несколько базовых c полей.

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

  // some other fields without references
}

Далее у меня есть объект graph . Этот содержит несколько графических узлов . Таким образом, вы можете иметь несколько графов, и каждый из них имеет свои собственные графовые узлы. Сам граф должен знать, какой graphNode является первым в графе. Поэтому я попытался настроить ссылку внешнего ключа на сущность graphNode.

  • может быть несколько графов
  • каждый граф имеет один graphNode в качестве начального узла
  • несколько графовых узлов на граф

.

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

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

  @ManyToOne(
    () => GraphNode,
    graphNode => graphNode.id,
  )
  @JoinColumn({ name: 'startNodeId' })
  public startNode: GraphNode;
}

Последним объектом является graphNodes . Каждый graphNode представляет модуль в одном графе. Он также знает о своих преемниках successGraphNodeId и errorGraphNodeId . Важно, чтобы у этой сущности был составной первичный ключ, потому что, если вы хотите получить GraphNode, вы также должны передать идентификатор графа. По сути, это случаи использования

  • . GraphNode представляет один модуль.
  • . Для каждого графа существует несколько узлов GraphNode
  • . GraphNode может ссылаться на себя как преемник (успех / ошибка. )
  • наследник графаNode может быть нулевым (успех / ошибка)
  • наследник графаNode должен быть GraphNode, который уже существует в этом графике

.

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

  @PrimaryColumn()
  public graphId: string; // composite key https://github.com/typeorm/typeorm/blob/master/sample/sample27-composite-primary-keys/entity/Post.ts

  @ManyToOne(
    () => Graph,
    graph => graph.id,
  )
  @JoinColumn({ name: 'graphId' })
  public graph: Graph;

  @Column()
  public moduleId: string;

  @ManyToOne(
    () => Module,
    module => module.id,
  )
  @JoinColumn({ name: 'moduleId' })
  public module: Module;

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

  @ManyToOne(
    () => GraphNode,
    graphNode => graphNode.id,
  )
  @JoinColumn({ name: 'successGraphNodeId' })
  public successGraphNode?: GraphNode;

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

  @ManyToOne(
    () => GraphNode,
    graphNode => graphNode.id,
  )
  @JoinColumn({ name: 'errorGraphNodeId' })
  public errorGraphNode?: GraphNode;
}

При запуске приложения, к сожалению, я получаю эту ошибку

QueryFailedError: Foreign key constraint »FK_0e4022833a9efc062c01637e552« cannot be implemented
    at new QueryFailedError (...\references-reproduction\node_modules\typeorm\error\QueryFailedError.js:11:28)
    at Query.callback (...\references-reproduction\node_modules\typeorm\driver\postgres\PostgresQueryRunner.js:176:38)
    at Query.handleError (...\references-reproduction\node_modules\pg\lib\query.js:145:17)
    at Connection.connectedErrorMessageHandler (...\references-reproduction\node_modules\pg\lib\client.js:214:17)
    at Connection.emit (events.js:223:5)
    at Socket.<anonymous> (...\references-reproduction\node_modules\pg\lib\connection.js:134:12)
    at Socket.emit (events.js:223:5)
    at addChunk (_stream_readable.js:309:12)
    at readableAddChunk (_stream_readable.js:290:11)
    at Socket.Readable.push (_stream_readable.js:224:10)

Кажется, моя сущность неверна. Кто-то знает, что здесь не так? Пожалуйста, дайте мне знать, если вам нужна дополнительная информация или мне нужно обновить репозиторий.

Заранее спасибо


Обновление

I смог воспроизвести его с двумя небольшими объектами. Существует только связь между графом

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

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

  @ManyToOne(
    () => Node,
    node => node.id,
  )
  @JoinColumn({ name: 'startNodeId' })
  public node: Node;
}

и его узлами

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

  @PrimaryColumn()
  public graphId: string;

  @ManyToOne(
    () => Graph,
    graph => graph.id,
  )
  @JoinColumn({ name: 'graphId' })
  public graph: Graph;
}

. Как уже упоминалось ранее, проблема, похоже, основана на составном первичном ключе. Я не хочу преобразовывать основной столбец graphId узла в столбец basi c, потому что это было бы плохим дизайном базы данных ...

Ответы [ 3 ]

2 голосов
/ 03 марта 2020

Не думаю, что ваша проблема в составном ключе. Для меня ваша модель имеет несколько fl aws:

  • Оба Graph и Node имеют ManyToOne по отношению друг к другу. Но из того, что я понял из вашего объяснения, Узел прикреплен только к одному Графику, поэтому в Graph это должен быть OneToMany, представляющий список Nodes:
@OneToMany(() => Node)
public nodes: Node[];
  • Второй аргумент аннотации ManyToOne должен быть атрибутом обратной стороны, но вы использовали его вместо ссылки на первичный ключ. Вот что у вас должно быть:
class Graph {
  @OneToMany(() => Node, node => node.graph)
  public nodes: Node[];
}

class Node {
  @ManyToOne(() => Graph, graph => graph.nodes)
  public graph: Graph;
}

Для JoinColumn typeorm должен автоматически принимать то, что вы указали, с основными столбцами в каждой сущности.

0 голосов
/ 02 марта 2020

Вы используете ограничение внешнего ключа в своих сущностях как:

@ManyToOne(
    () => GraphNode,
    graphNode => graphNode.id,
)

и соответственно в другой сущности. Вы получаете ошибку, потому что ваша текущая база данных не удовлетворяет этому правилу. Итак, самый простой способ получить эту работу - это:

  1. Удалить текущую базу данных
  2. Создать новую базу данных
  3. Изменить конфигурацию для подключения к новой созданной базе данных.

При этом все вновь созданные записи будут работать в соответствии с обновленными ограничениями в базе данных. Надеюсь, что это работает для вас.

0 голосов
/ 01 марта 2020

У вас есть два первичных ключа в GraphNode

@PrimaryGeneratedColumn('uuid')
public id: string;

@PrimaryColumn()
public graphId: string;

, поэтому fk для самопровозглашенных success- и errorGraphNode не будет работать. Удалите один ПК и работайте с другим.

...