C# Visual Studio SQL数据库,执行批处理时出错(消息1785)
我已在MS visual studio项目的基于服务的数据库(Microsoft SQL)中创建了下表:C# Visual Studio SQL数据库,执行批处理时出错(消息1785),c#,sql,sql-server,asp.net-mvc,visual-studio,C#,Sql,Sql Server,Asp.net Mvc,Visual Studio,我已在MS visual studio项目的基于服务的数据库(Microsoft SQL)中创建了下表: CREATE TABLE [dbo].[users] ( [phone_number] VARCHAR (50) NOT NULL, [name] VARCHAR (50) NOT NULL, [picture] VARCHAR (50) NOT NULL, [password] VARCHAR (50) NOT NULL, CONST
CREATE TABLE [dbo].[users] (
[phone_number] VARCHAR (50) NOT NULL,
[name] VARCHAR (50) NOT NULL,
[picture] VARCHAR (50) NOT NULL,
[password] VARCHAR (50) NOT NULL,
CONSTRAINT [PK_users] PRIMARY KEY ([phone_number])
);
之后,当我尝试添加下表时,我得到了错误:
执行批处理时出错
创建更新脚本时不会出现警告,数据库中也没有数据。我尝试从头开始重新创建所有内容,但错误仍然存在。我可能做错了什么
编辑:如果我从任何一个外键约束中删除“删除级联”和“更新级联”,则错误消失,在任何其他组合中删除都没有帮助。这些约束有什么问题吗?我在SSMS中执行代码时遇到了这个错误。我做了一个快速搜索,有很多关于这个主题的信息供你研究 Msg 1785,16级,状态0,第2行引入外键约束 表“位置”上的“FK_2”可能导致循环或多个级联路径。 指定在删除时不执行操作或在更新时不执行操作,或修改其他 外键约束。Msg 1750,16级,状态0,第2行无法访问 创建约束或索引。请参阅前面的错误 根据聊天记录编辑: 我认为,基于您删除该位置的愿望,最好您这样做。保持FK的完整性,并可能创建一个存储过程来删除用户
给出了MSDN上关于 您收到此错误消息是因为在SQL Server中,表不能 在所有级联引用的列表中多次出现 由DELETE或UPDATE语句启动的操作。 例如,级联引用操作树必须只有 级联引用操作上特定表的一条路径 树 以及他们声明的解决方法 您可以通过几种方式强制引用完整性。声明的 引用完整性(DRI)是最基本的方法,但它也是 最不灵活的方式。如果你需要更多的灵活性,但你仍然想要一个 高度的完整性,您可以使用触发器 我们可以选择以这种方式创建触发器来避免这个问题
ALTER TRIGGER [dbo].[CascadeDeleteNumber]
ON [dbo].[users]
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM location WHERE Sender = (select phone_number from deleted)
DELETE FROM location WHERE Reciever = (select phone_number from deleted)
DELETE FROM users WHERE phone_number = (select phone_number from deleted)
END
DELETE触发器是一个而不是,因为AFTER触发器从未被引用完整性检查阻止执行。取而代之允许我们先删除位置表中的记录,然后删除用户表中的记录,从而保留引用完整性
对于更新,我们可以使用另一个触发器,但这更棘手。我没有找到在不破坏引用完整性的情况下正确更新电话号码的方法,因此我设法临时更改电话号码,删除引用完整性,更新所需记录,然后恢复引用完整性
ALTER TRIGGER [dbo].[CascadeUpdateNumber]
ON [dbo].[users]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @old_num nvarchar(50)
DECLARE @new_num nvarchar(50)
DECLARE @new_name varchar(50)
DECLARE @new_img varchar(50)
DECLARE @new_pwd varchar(50)
SELECT @old_num = phone_number FROM deleted
SELECT @new_num = phone_number, @new_name = name, @new_img = picture,
@new_pwd = password FROM inserted
ALTER TABLE [dbo].[location] DROP CONSTRAINT [FK_1]
ALTER TABLE [dbo].[location] DROP CONSTRAINT [FK_2]
UPDATE location SET sender = @new_num WHERE sender = @old_num
UPDATE location SET reciever = @new_num WHERE reciever = @old_num
UPDATE users SET phone_number = @new_num, name = @new_name,
picture=@new_img, password=@new_pwd
WHERE phone_number = @old_num
ALTER TABLE [dbo].[location] WITH CHECK
ADD CONSTRAINT [FK_3] FOREIGN KEY([sender])
REFERENCES [dbo].[users] ([phone_number])
ALTER TABLE [dbo].[location] WITH CHECK
ADD CONSTRAINT [FK_4] FOREIGN KEY([reciever])
REFERENCES [dbo].[users] ([phone_number])
END
老实说,从表上并发更新的角度来看,我不知道这种方法是否安全 数字是非常糟糕的列名…所以发送方和接收方对于数字列都是FK?你是说名字吗?@jarlh:对不起,这个号码是用来存储电话号码的。@Steve:不,我的意思和我现在使用的完全一样,意思是一个电话号码可以是发送者,另一个可以是接收者,他们的发送关系或记录保存在位置表中。我感谢你的关注,你能详细说明一下在哪种情况下它会导致循环吗?我没有读太多,但在我看来,因为两个外键都指向同一个表中的同一个字段,所以可能会有冲突。例如,如果删除用户,位置记录将被删除。如果指定两次,将尝试两次删除相同的记录。通常,FK指向主键,并且只引用一次。我不清楚你设计的意图,链接到电话号码。我明白你的意思,那么,维护从phone_number_1发送到phone_number_2的消息的最佳模式是什么,以便在父表中删除或更新这两个消息时自动更新或删除它们。就我个人而言,我不会让发件人和收件人字段填充电话号码。它们只是与用户表上的ID相关的整数。您只需要对其中一个外键进行约束,删除用户将删除位置。即使我使用int id并将其用作FK而不是电话号码,则不需要更新cascade,但仍然需要删除cascade。如果我在其中一个外键上使用on delete cascade,比如sender,那么如果从用户表中删除了接收方,那又怎么样?啊哈!我将这个问题解释为反向级联(位置上的触发器级联到用户)。那会有点混乱;)@Steve:如果我使用trigger,那么我必须删除外键约束,就像添加trigger之后一样,当我尝试删除或更新父表中的主键时,它会显示错误。我不想删除外键约束,因为它会导致数据不一致。如何通过触发器确保数据一致性?我明白了,需要将触发器更改为而不是。更新部分很棘手,我不确定这在非常高的并发性场景中是否安全,但它也适用于引用。更新
ALTER TRIGGER [dbo].[CascadeUpdateNumber]
ON [dbo].[users]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @old_num nvarchar(50)
DECLARE @new_num nvarchar(50)
DECLARE @new_name varchar(50)
DECLARE @new_img varchar(50)
DECLARE @new_pwd varchar(50)
SELECT @old_num = phone_number FROM deleted
SELECT @new_num = phone_number, @new_name = name, @new_img = picture,
@new_pwd = password FROM inserted
ALTER TABLE [dbo].[location] DROP CONSTRAINT [FK_1]
ALTER TABLE [dbo].[location] DROP CONSTRAINT [FK_2]
UPDATE location SET sender = @new_num WHERE sender = @old_num
UPDATE location SET reciever = @new_num WHERE reciever = @old_num
UPDATE users SET phone_number = @new_num, name = @new_name,
picture=@new_img, password=@new_pwd
WHERE phone_number = @old_num
ALTER TABLE [dbo].[location] WITH CHECK
ADD CONSTRAINT [FK_3] FOREIGN KEY([sender])
REFERENCES [dbo].[users] ([phone_number])
ALTER TABLE [dbo].[location] WITH CHECK
ADD CONSTRAINT [FK_4] FOREIGN KEY([reciever])
REFERENCES [dbo].[users] ([phone_number])
END