New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Failure creating a migration with MSSQL: Introducing FOREIGN KEY constraint '...' on table '...' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
#5782
Failure creating a migration with MSSQL: Introducing FOREIGN KEY constraint '...' on table '...' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
#5782
Comments
This comment has been minimized.
This comment has been minimized.
Introducing FOREIGN KEY constraint '...' on table '...' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
This is going to be solved with the PR prisma/prisma-engines#1947 What this means for this problem is, if getting an error from a cascade loops, you can manually define the Instructions on how to use this, and a place to give feedback: #7816 |
This has now been released as a preview feature behind a preview feature flag. You can read about it in the release notes for 2.26.0: https://github.com/prisma/prisma/releases/tag/2.26.0 If you have any feedback, please use this issue: #7816 |
This should now work with the |
Let's say this a bit differently: if getting this error, we have now tools to replace the |
Upgrading to The initial schema: datasource db {
provider = "sqlserver"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["microsoftSqlServer", "referentialActions"]
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
email String @unique
name String?
comments Comment[]
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
comments Comment[]
tags Tag[] @relation("TagToPost")
}
model Comment {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
comment String
writtenById Int
postId Int
writtenBy User @relation(fields: [writtenById], references: [id])
post Post @relation(fields: [postId], references: [id])
}
model Tag {
id Int @id @default(autoincrement())
tag String @unique
posts Post[] @relation("TagToPost")
} Leads to this migration with -- CreateTable
CREATE TABLE [dbo].[User] (
[id] INT NOT NULL IDENTITY(1,1),
[createdAt] DATETIME2 NOT NULL CONSTRAINT [DF__User__createdAt] DEFAULT CURRENT_TIMESTAMP,
[email] NVARCHAR(1000) NOT NULL,
[name] NVARCHAR(1000),
CONSTRAINT [PK__User__id] PRIMARY KEY ([id]),
CONSTRAINT [User_email_unique] UNIQUE ([email])
);
-- CreateTable
CREATE TABLE [dbo].[Post] (
[id] INT NOT NULL IDENTITY(1,1),
[createdAt] DATETIME2 NOT NULL CONSTRAINT [DF__Post__createdAt] DEFAULT CURRENT_TIMESTAMP,
[title] NVARCHAR(1000) NOT NULL,
[content] NVARCHAR(1000),
[published] BIT NOT NULL CONSTRAINT [DF__Post__published] DEFAULT 0,
[authorId] INT NOT NULL,
CONSTRAINT [PK__Post__id] PRIMARY KEY ([id])
);
-- CreateTable
CREATE TABLE [dbo].[Comment] (
[id] INT NOT NULL IDENTITY(1,1),
[createdAt] DATETIME2 NOT NULL CONSTRAINT [DF__Comment__createdAt] DEFAULT CURRENT_TIMESTAMP,
[comment] NVARCHAR(1000) NOT NULL,
[writtenById] INT NOT NULL,
[postId] INT NOT NULL,
CONSTRAINT [PK__Comment__id] PRIMARY KEY ([id])
);
-- CreateTable
CREATE TABLE [dbo].[Tag] (
[id] INT NOT NULL IDENTITY(1,1),
[tag] NVARCHAR(1000) NOT NULL,
CONSTRAINT [PK__Tag__id] PRIMARY KEY ([id]),
CONSTRAINT [Tag_tag_unique] UNIQUE ([tag])
);
-- CreateTable
CREATE TABLE [dbo].[_TagToPost] (
[A] INT NOT NULL,
[B] INT NOT NULL,
CONSTRAINT [_TagToPost_AB_unique] UNIQUE ([A],[B])
);
-- CreateIndex
CREATE INDEX [_TagToPost_B_index] ON [dbo].[_TagToPost]([B]);
-- AddForeignKey
ALTER TABLE [dbo].[Post] ADD CONSTRAINT [FK__Post__authorId] FOREIGN KEY ([authorId]) REFERENCES [dbo].[User]([id]) ON DELETE NO ACTION ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[Comment] ADD CONSTRAINT [FK__Comment__writtenById] FOREIGN KEY ([writtenById]) REFERENCES [dbo].[User]([id]) ON DELETE NO ACTION ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[Comment] ADD CONSTRAINT [FK__Comment__postId] FOREIGN KEY ([postId]) REFERENCES [dbo].[Post]([id]) ON DELETE NO ACTION ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[_TagToPost] ADD CONSTRAINT [FK___TagToPost__A] FOREIGN KEY ([A]) REFERENCES [dbo].[Post]([id]) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[_TagToPost] ADD CONSTRAINT [FK___TagToPost__B] FOREIGN KEY ([B]) REFERENCES [dbo].[Tag]([id]) ON DELETE CASCADE ON UPDATE CASCADE;
Deploying that with
or
When you then add a datasource db {
provider = "sqlserver"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["microsoftSqlServer", "referentialActions"]
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
email String @unique
name String?
comments Comment[]
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
comments Comment[]
tags Tag[] @relation("TagToPost")
}
model Comment {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
comment String
writtenById Int
postId Int
writtenBy User @relation(fields: [writtenById], references: [id])
post Post @relation(fields: [postId], references: [id], onUpdate: NoAction)
}
model Tag {
id Int @id @default(autoincrement())
tag String @unique
posts Post[] @relation("TagToPost")
} - post Post @relation(fields: [postId], references: [id])
+ post Post @relation(fields: [postId], references: [id], onUpdate: NoAction) Will give you this SQL now with: -- CreateTable
CREATE TABLE [dbo].[User] (
[id] INT NOT NULL IDENTITY(1,1),
[createdAt] DATETIME2 NOT NULL CONSTRAINT [DF__User__createdAt] DEFAULT CURRENT_TIMESTAMP,
[email] NVARCHAR(1000) NOT NULL,
[name] NVARCHAR(1000),
CONSTRAINT [PK__User__id] PRIMARY KEY ([id]),
CONSTRAINT [User_email_unique] UNIQUE ([email])
);
-- CreateTable
CREATE TABLE [dbo].[Post] (
[id] INT NOT NULL IDENTITY(1,1),
[createdAt] DATETIME2 NOT NULL CONSTRAINT [DF__Post__createdAt] DEFAULT CURRENT_TIMESTAMP,
[title] NVARCHAR(1000) NOT NULL,
[content] NVARCHAR(1000),
[published] BIT NOT NULL CONSTRAINT [DF__Post__published] DEFAULT 0,
[authorId] INT NOT NULL,
CONSTRAINT [PK__Post__id] PRIMARY KEY ([id])
);
-- CreateTable
CREATE TABLE [dbo].[Comment] (
[id] INT NOT NULL IDENTITY(1,1),
[createdAt] DATETIME2 NOT NULL CONSTRAINT [DF__Comment__createdAt] DEFAULT CURRENT_TIMESTAMP,
[comment] NVARCHAR(1000) NOT NULL,
[writtenById] INT NOT NULL,
[postId] INT NOT NULL,
CONSTRAINT [PK__Comment__id] PRIMARY KEY ([id])
);
-- CreateTable
CREATE TABLE [dbo].[Tag] (
[id] INT NOT NULL IDENTITY(1,1),
[tag] NVARCHAR(1000) NOT NULL,
CONSTRAINT [PK__Tag__id] PRIMARY KEY ([id]),
CONSTRAINT [Tag_tag_unique] UNIQUE ([tag])
);
-- CreateTable
CREATE TABLE [dbo].[_TagToPost] (
[A] INT NOT NULL,
[B] INT NOT NULL,
CONSTRAINT [_TagToPost_AB_unique] UNIQUE ([A],[B])
);
-- CreateIndex
CREATE INDEX [_TagToPost_B_index] ON [dbo].[_TagToPost]([B]);
-- AddForeignKey
ALTER TABLE [dbo].[Post] ADD CONSTRAINT [FK__Post__authorId] FOREIGN KEY ([authorId]) REFERENCES [dbo].[User]([id]) ON DELETE NO ACTION ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[Comment] ADD CONSTRAINT [FK__Comment__writtenById] FOREIGN KEY ([writtenById]) REFERENCES [dbo].[User]([id]) ON DELETE NO ACTION ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[Comment] ADD CONSTRAINT [FK__Comment__postId] FOREIGN KEY ([postId]) REFERENCES [dbo].[Post]([id]) ON DELETE NO ACTION ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE [dbo].[_TagToPost] ADD CONSTRAINT [FK___TagToPost__A] FOREIGN KEY ([A]) REFERENCES [dbo].[Post]([id]) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE [dbo].[_TagToPost] ADD CONSTRAINT [FK___TagToPost__B] FOREIGN KEY ([B]) REFERENCES [dbo].[Tag]([id]) ON DELETE CASCADE ON UPDATE CASCADE;
- ALTER TABLE [dbo].[Comment] ADD CONSTRAINT [FK__Comment__postId] FOREIGN KEY ([postId]) REFERENCES [dbo].[Post]([id]) ON DELETE NO ACTION ON UPDATE CASCADE;
+ ALTER TABLE [dbo].[Comment] ADD CONSTRAINT [FK__Comment__postId] FOREIGN KEY ([postId]) REFERENCES [dbo].[Post]([id]) ON DELETE NO ACTION ON UPDATE NO ACTION; You can successfully migrate the schema:
While there is now a manual way to fix this, I don't think this is enough to close this issue yet. We now have the tools to build a real solution, but will have to figure out what that looks like. (ideas: schema validation, better error message) |
Recap of an internal discussion about this: We have 3 options:
Discussion of these options:
Additional information:
Further thoughts about how to get out of the error situation, even with #7641 implemented:
|
Bug description
I attempted to use Prisma Migrate (2.17.0) to create a migration from the Prisma schema below and got the following error:
It seems that the combination of defaulting to cascading deletes and a circular relation (between
User : Post : Comment : User
) causes the SQL to be invalid.How to reproduce
npx prisma migrate dev --preview-feature
to generate and apply the migrationThis is where the error shows up.
I was able to resolve this by updating the
FK__Comment__postId
constraint in the migration SQ.Expected behavior
It should generate an executable migration.
Prisma information
Prisma schema:
Environment & setup
mcr.microsoft.com/mssql/server:2019-latest
)The text was updated successfully, but these errors were encountered: