2012-01-18 34 views
1

处理具有FK参考约束的数据库行的删除的最佳做法是什么?我的目标是向最终用户展示更多用户友好的错误消息。请注意,我不想t want to delete department with employees and that I don t想要在表上进行级联删除。使用外键删除行时用户友好的错误消息参考约束

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

-- 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] 

如果一个人想从部门表,在该行的员工表中引用删除行。应该怎么做?

  1. 之前执行DELETE语句,检查是否排在员工表中引用而优雅地恢复错误GUI(与eployee名单如有必要)

  2. 执行DELETE语句,并做捕获异常,如:

    catch (SqlException ex) 
    { 
        switch (ex.Number) 
         case 547: HandleErrorGracefully() 
    } 
    
  3. 一些其他的方式?

将是很好,如果有人有一些代码/链接到应用程序样本...

+0

可能的重复http://stackoverflow.com/questions/7944559/how-to-manipulate-sqlexception-message-into-user-friendly-message – 2012-01-18 12:51:53

回答

5

方案三:既做1和2

有专人之间另一个进程插入潜力检查(通过)和删除失败。

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

+0

我喜欢选项3,但我不认为它应该被执行在任何情况下:如果是这样,那么每个数据库约束将在'前端'代码中被重新实现,从而增加它们在语义上不等同的风险,必须在两个地方更改代码的维护开销等。理想情况下,两者都应该使用相同的规则引擎:) – onedaywhen 2012-01-18 13:50:22

+0

@onedaywhen:通过“检查”我的意思是某种“IF NOT EXISTS .. DELETE”,在存储过程中也许 – gbn 2012-01-18 13:55:29

0

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

+0

对不起,我没有写过它,但是,我不想删除部门与员工,我不想在表上进行级联删除。 – 2012-01-18 13:08:35

2

更好!

显示部门和它的员工数量,只启用删除选项,如果员工数为0

依靠参照完整性停止编码错误,而不是用户的...

+0

可见计数为零可能已过期,因此DELETE将失败并需要进行检查(根据我的回答) – gbn 2012-01-18 13:12:48

+1

“依靠参照完整性来停止编码错误” - 不要依赖!业务规则在数据库约束中的错误实现(或省略)本身就是编码错误。 – onedaywhen 2012-01-18 13:44:56

+0

@gbn。当然它可能已经过时了。其他人可能已经删除了整个事情!那有多可能?是否值得额外的代码的努力,以更好的与外键违规,如果你有改善.. – 2012-01-18 18:46:13

0

我过去几天/几个月也有同样的问题。在大量的谷歌搜索之后,我使用SqlHelper类来解决在DAL中转换错误消息的问题。

我用下面的方式来处理这个问题。

创建自Exception类派生的如图中diagram一些类。

DalExceptionClass:Exception 

ForeignKeyException: DalException 
在提供SQLHelper

public void ExecuteNonQuery(string procedure) 
{ 
    try 
    { 
     con.open() 
     cmd.executenonquery(); 
     con.close(); 
     //Sql Exception is raised 
    } 
    catch(SqlException ex) 
    { 
     throw TranslateException(ex); 
    } 
} 

在链接使用代码,我转换为SQL例外DalException而不是例外

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,我会处理DalException仅将返回我的异常消息

“{0}失败,{1}必须是唯一的” 使用的String.format(MSG, “插入“,”客户“);

这会发送一个异常给BAL,因为“插入失败,客户端必须是唯一的”,这可能有点粒状信息。

编辑

这将在DAL作为

处理
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"); 
     } 
    } 

参考

How to manipulate SqlException message into user friendly message

http://www.reflectionit.nl/DAL.aspx

What should be the strategy to handle the sql exceptions?

+0

因此,您将等待异常,并且不会检查/验证行是否被引用?有没有理由不这样做? – 2012-01-18 13:30:07

+0

@IvanMilosavljevic:是的,因为我将有所有的限制,我不会使用Cascade,因为我的设计说不要自动删除从属记录。所以contstraints将阻止我删除正在使用的记录。因此,如果我的目标是删除记录,那么我将发出删除查询。如果我真的需要检查是否正在使用记录。那么它应该是一个单独的选择查询,将推动我的验证业务。 – 2012-01-18 13:36:44

+0

我知道这可能不是最好的方法,但使用这个我可以接近更多的用户友好的消息。但是,我们从Sql Server迁移到其他服务器,然后我们可能不会收到ErrorNumber,但只能在TranslateException方法中处理。其余的代码不会受到影响。 – 2012-01-18 13:40:42