处理具有FK REFERENCE约束的db行的最佳做法是什么?我的目标是向最终用户提供更加用户友好的错误消息。请注意,我不想t want to delete department with employees and that I don
想要在表上进行级联删除。
例如,如果我们有两个表:
-- 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()
}
其他方式?
如果有人拥有应用程序示例的代码/链接,那会很好......
答案 0 :(得分:5)
选项3:同时执行1和2
有人可能会在检查(通过)和删除失败之间插入另一个进程。
在这种情况下,您可以向用户说“抱歉,出现问题”(但记录下来),看看他们是否想再试一次。然后检查将拦截它。
答案 1 :(得分:2)
更好!
显示其中的部门和员工人数,只有员工人数为0才启用删除选项。
依靠引用完整性来停止编码错误,而不是用户错误...
答案 2 :(得分:0)
@ gbn的答案是一个很好的方法。但您也可以将ON DELETE CASCADE
放在外键关系上,并询问用户“您确定要删除此部门及其所有员工吗?”。
答案 3 :(得分: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 Exceptions转换为DalException而不是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中,我将只处理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