Visual Studio SQL数据库,正在执行批处理时发生错误(Msg 1785)

时间:2016-06-08 12:03:45

标签: 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, 
    CONSTRAINT [PK_users] PRIMARY KEY ([phone_number])
);

之后,当我尝试添加下表时,我收到错误:

  

批处理执行时发生错误

CREATE TABLE [dbo].[location] (
    [location_id] INT  NOT NULL PRIMARY KEY IDENTITY (1, 1),
    [sender]      VARCHAR (50) NOT NULL,
    [reciever]    VARCHAR (50) NOT NULL,
    [latitude]    FLOAT (53)   NOT NULL,
    [longitude]   FLOAT (53)   NOT NULL,
    CONSTRAINT [FK_1] FOREIGN KEY ([sender]) REFERENCES [dbo].[users] ([phone_number]) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT [FK_2] FOREIGN KEY ([reciever]) REFERENCES [dbo].[users] ([phone_number]) ON DELETE CASCADE ON UPDATE CASCADE
);

创建更新脚本时没有出现警告,并且数据库中也没有数据。我尝试从头开始重新创建所有内容,但错误仍然存​​在。我可能做错了什么?

编辑:如果我同时删除" ON DELETE CASCADE"则错误消失和" ON UPDATE CASCADE"从任何一个外键约束中,删除任何其他组合都没有帮助。那些限制有什么不对?

2 个答案:

答案 0 :(得分:2)

鉴于MSDN上有关Msg 1785

的文档
  

您收到此错误消息,因为在SQL Server中,表不能   在所有级联参照的列表中出现不止一次   由DELETE或UPDATE语句启动的操作。   例如,级联引用操作树必须只有   级联引用操作的特定表的一个路径   树。

及其陈述的解决方法

  

您可以通过多种方式强制实施参照完整性。陈述   参考完整性(DRI)是最基本的方式,但它也是   最灵活的方式。如果你需要更多的灵活性,但你仍然想要一个   高度完整性,你可以使用触发器

我们可以选择以这种方式避免这个问题创建TRIGGER

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触发器是一个INSTEAD OF,因为AFTER触发器永远不会被检查参照完整性所阻止。 INSTEAD OF允许我们先删除位置表中的记录,然后删除users表中的记录,使参照完整性快乐

对于UPDATE我们可以使用另一个TRIGGER,但它更棘手 我没有找到正确更新phone_number的方法而不破坏引用完整性,因此我设法更改phone_number暂时删除引用完整性,更新所需记录,然后重新引用参照完整性。

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

从表格上的并发更新的角度来看,我不知道这种方法是否安全。

答案 1 :(得分:1)

我在SSMS中执行代码时遇到此错误。我做了一个快速搜索,有很多关于这个主题的信息供你研究。

  

消息1785,级别16,状态0,行2引入FOREIGN KEY约束   ' FK_2'在桌子上的位置'可能会导致循环或多个级联路径。   指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他   FOREIGN KEY约束。 Msg 1750,Level 16,State 0,Line 2不能   创建约束或索引。查看以前的错误。

基于聊天的编辑:

我认为根据您删除位置的愿望,如果您这样做,那将是最好的。保持FK的完整性,并可能创建一个删除用户的存储过程

  1. 开始交易
  2. 从sender = userid或reciever = userid的位置删除(如果你坚持使用PK,则删除phone_number)
  3. 从用户表中删除
  4. 提交交易