C# 删除带有外键引用约束的行时的用户友好错误消息

C# 删除带有外键引用约束的行时的用户友好错误消息,c#,.net,sql,validation,ado.net,C#,.net,Sql,Validation,Ado.net,处理删除具有FK引用约束的db行的最佳实践是什么?我的目标是向最终用户提供更友好的错误消息。请注意,我不想删除有员工的部门,也不想对表进行级联删除 例如,如果我们有两个表: -- Department table CREATE TABLE [dbo].[Department]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

处理删除具有FK引用约束的db行的最佳实践是什么?我的目标是向最终用户提供更友好的错误消息。请注意,我不想删除有员工的部门,也不想对表进行级联删除

例如,如果我们有两个表:

-- Department table
CREATE TABLE [dbo].[Department](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

-- Employee table
CREATE TABLE [dbo].[Employee](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [DepartmentId] [int] NULL,
 CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[Employee]  WITH CHECK ADD  CONSTRAINT [FK_Employee_Department] FOREIGN KEY([DepartmentId])
REFERENCES [dbo].[Department] ([Id])
GO
ALTER TABLE [dbo].[Employee] CHECK CONSTRAINT [FK_Employee_Department]
若要从department表中删除行,则该行在employee表中引用。该怎么办

  • 在执行DELETE语句之前,检查employee表中是否引用了行,并将错误优雅地返回到GUI(必要时使用eployee列表)

  • 执行DELETE语句并捕获异常,如:

    catch (SqlException ex) 
    { 
        switch (ex.Number) 
           case 547: HandleErrorGracefully()
    } 
    
  • 还有别的办法吗


  • 如果有人有应用程序示例的代码/链接,那就太好了…

    选项3:同时执行1和2

    有可能有人在检查(通过)和删除失败之间插入另一个进程


    在这种情况下,您可以对用户说“对不起,出了问题”(但要记录),然后看看他们是否想再试一次。然后检查将截取它。

    选项3:同时执行1和2

    有可能有人在检查(通过)和删除失败之间插入另一个进程


    在这种情况下,您可以对用户说“对不起,出了问题”(但要记录),然后看看他们是否想再试一次。然后检查将拦截它。

    @gbn的答案是一个很好的方法。但是,您也可以在外键关系的DELETE CASCADE上设置
    ,并询问用户类似“您确定要删除此部门及其所有员工吗?”。

    @gbn的回答是一个很好的方法。但是,您也可以在外键关系的DELETE CASCADE上放置
    ,并询问用户类似“您确定要删除此部门及其所有员工吗?”。

    友好点

    显示其中的部门和员工人数,仅当员工人数为0时才启用删除选项


    依靠引用完整性来停止编码错误,而不是用户错误…

    更好

    显示其中的部门和员工人数,仅当员工人数为0时才启用删除选项


    依靠引用完整性来停止编码错误,而不是用户错误…

    几天前/几个月前,我也遇到过同样的问题。经过大量的谷歌搜索,我终于解决了使用SqlHelper类在DAL中翻译错误消息的问题

    我用以下方法处理这个问题

    创建了一些从Exception类派生的类,如中所示

    在SqlHelper中

    public void ExecuteNonQuery(string procedure)
    {
        try
        {
          con.open()
           cmd.executenonquery();
          con.close();
          //Sql Exception is raised
        }
        catch(SqlException ex)
        {
            throw TranslateException(ex);
        }
    }
    
    使用链接中的代码,我将Sql异常转换为DaleException,而不是Exception

    protected DalException TranslateException(SqlException ex) { 
        DalException dalException = null; 
    
        // Return the first Custom exception thrown by a RAISERROR 
        foreach (SqlError error in ex.Errors) { 
            if (error.Number >= 50000) { 
                dalException = new DalException(error.Message, ex); 
            } 
        } 
    
        if (dalException == null) { 
            // uses SQLServer 2000 ErrorCodes 
            switch (ex.Number) { 
                case 2601: 
                    // Unique Index/Constriant Violation 
                    dalException = new DalUniqueConstraintException("{0} failed, {1} must be unique", ex); 
                    break; 
                default: 
                    // throw a general DAL Exception 
                    dalException = new DalException(ex.Message, ex); 
                    break; 
            } 
        } 
    
        // return the error 
        return dalException; 
    } 
    
    请注意案例2601:

    我在这里发送了自定义消息

    现在在我的DAL中,我将只处理DaleException,它将返回异常消息作为

    “{0}失败,{1}必须是唯一的”,使用string.Format(msg, “插入”、“客户”)

    这将向BAL发送一个异常,即“插入失败,客户端必须唯一”,这可能是一条一般性消息

    编辑

    这将在DAL as处理

        public Client Insert()
        {
        try
           {
            _repository.Insert(client);
           } 
        catch(DalException ex)
           {
    //wrap message since, error will always be in client entity as client's method is being called. Also, insertion is being failed.
             throw new BusinessException(string.Format(ex.message), "Insertion", "Client");
           }
        }
    
    参考资料


    几天前/几个月前,我也有同样的问题。经过大量的谷歌搜索,我终于解决了使用SqlHelper类在DAL中翻译错误消息的问题

    我用以下方法处理这个问题

    创建了一些从Exception类派生的类,如中所示

    在SqlHelper中

    public void ExecuteNonQuery(string procedure)
    {
        try
        {
          con.open()
           cmd.executenonquery();
          con.close();
          //Sql Exception is raised
        }
        catch(SqlException ex)
        {
            throw TranslateException(ex);
        }
    }
    
    使用链接中的代码,我将Sql异常转换为DaleException,而不是Exception

    protected DalException TranslateException(SqlException ex) { 
        DalException dalException = null; 
    
        // Return the first Custom exception thrown by a RAISERROR 
        foreach (SqlError error in ex.Errors) { 
            if (error.Number >= 50000) { 
                dalException = new DalException(error.Message, ex); 
            } 
        } 
    
        if (dalException == null) { 
            // uses SQLServer 2000 ErrorCodes 
            switch (ex.Number) { 
                case 2601: 
                    // Unique Index/Constriant Violation 
                    dalException = new DalUniqueConstraintException("{0} failed, {1} must be unique", ex); 
                    break; 
                default: 
                    // throw a general DAL Exception 
                    dalException = new DalException(ex.Message, ex); 
                    break; 
            } 
        } 
    
        // return the error 
        return dalException; 
    } 
    
    请注意案例2601:

    我在这里发送了自定义消息

    现在在我的DAL中,我将只处理DaleException,它将返回异常消息作为

    “{0}失败,{1}必须是唯一的”,使用string.Format(msg, “插入”、“客户”)

    这将向BAL发送一个异常,即“插入失败,客户端必须唯一”,这可能是一条一般性消息

    编辑

    这将在DAL as处理

        public Client Insert()
        {
        try
           {
            _repository.Insert(client);
           } 
        catch(DalException ex)
           {
    //wrap message since, error will always be in client entity as client's method is being called. Also, insertion is being failed.
             throw new BusinessException(string.Format(ex.message), "Insertion", "Client");
           }
        }
    
    参考资料


    可能重复可能重复抱歉,我没有写,但是,我不想删除有员工的部门,也不想对表进行级联删除。抱歉,我没有写,但是,我不想删除有员工的部门,也不想对表进行级联删除。可见的零计数可能已过期,因此删除将失败,需要进行检查(根据我的回答)“依赖引用完整性以停止编码错误”-不要依赖!将业务规则不正确地实现(或省略)到数据库约束中本身就是一个编码错误。@gbn。当然,它可能已经过时了。其他人可能已经删除了整个内容!这种可能性有多大?如果您已经改进了…@onedaywhen,如果我正在做一个db,那么是否值得花额外的代码来处理外键冲突呢。首先我做对了,然后我编码,如果在编码时我发现它不正确,我会停止,我会修复,我会重新测试,我会重新开始。我的方法是获得数据完整性,另一种方法是交叉手指。可见计数为零可能已过时,因此删除将失败,需要进行检查(根据我的回答)“依赖引用完整性停止编码错误”——不要依赖!将业务规则不正确地实现(或省略)到数据库约束中本身就是一个编码错误。@gbn。当然,它可能已经过时了。其他人可能已经删除了整个内容!这种可能性有多大?如果您已经改进了…@onedaywhen,如果我正在做一个db,那么是否值得花额外的代码来处理外键冲突呢。首先我做对了,然后我编码,如果在编码时我发现它不正确,我会停止,我会修复,我会重新测试,我会重新开始。我的方式