bza*_*fir 6 c# sql sql-server error-handling sqlexception
我使用SQL Server编写的数据库应用程序,使用sql server作为后端.为了数据完整性,我尝试在数据库级别上尽可能强制执行 - 关系,检查约束,触发器.
由于它们,如果数据不一致,则save/update/insert可能会失败,并且app会抛出SqlException.
我在UI中进行各种验证(如果输入的数据无效,则向用户显示有意义的信息),也在BL中,它将错误报告给用户提供给用户的UI.
但是,有些东西确实无法在应用程序中检查,并且由db处理:我的意思是当没有级联删除和用户尝试从主表中删除实体时删除错误等.
例如,员工表在很多关系中充当主人 - 员工经理,部门经理,收银员,团队负责人,团队成员等等.如果我添加一个没有涉及任何关系的新员工我可以删除它,但是用户尝试删除一个主要的关系,由于在DB级强制执行RI规则,删除失败(因为它应该),这没关系.
我在try ... catch中编写删除代码并处理异常,告诉用户他无法删除该员工.但我想给用户更有意义的信息 - 记录无法删除的原因.也许这只是一个测试员工记录,也被添加到测试团队.但是用户忘记了添加的内容,如果我能说"无法删除员工,因为它是团队T1的一部分",用户将知道先去T1团队,删除用户然后再尝试删除它.这是一个简单的例子,因为我说员工可以参与很多关系 - 在我的应用程序中我至少有20个.
解决方案是显示SqlException报告的消息,但这根本不优雅.首先,msg非常技术性 - 它谈论FK,PK,触发器,这对用户来说毫无意义并且会吓到它们.其次,我的应用程序使用多语言UI,所有菜单和消息都以用户选择的语言显示(在登录时或用户配置文件中选择).并且来自SqlException的消息是英语(如果我使用英语版本)或最差的,不太常见的语言,如德语或荷兰语,如果它发生sql server就是那种语言.
是否有任何通用或推荐的方法从sql异常中提取有意义的信息,以便能够向用户呈现有意义的消息(例如,什么关系或子表导致失败,或什么触发等).但我可以在程序中以独立于lang的方式测试,然后以用户友好的方式格式化我自己的错误消息?
你是如何处理这种情况的?
谢谢你的所有答案
(PS:很抱歉很长的帖子)
不幸的是,这里没有一个简单的答案.
涉及的工作量取决于来自业务层的错误消息的一致性.您将需要从"技术"错误消息到面向用户的消息进行某种形式的转换.
这应该是从您的错误消息到资源键进行某些形式的查找,这可以用来提取特定于语言的错误消息.但是,如果您需要解析消息以获取更多信息(例如:表名等),那么它会变得有点棘手.在这种情况下,您可能需要将错误消息映射到某种形式的正则表达式/处理器以及新的资源字符串.然后,您可以使用从原始错误中提取的信息格式化用户的字符串,并将其呈现给用户.
好吧,从数据库中,您只会收到这些技术消息,例如“违反外键关系 FK_something_to_another”等。
通常,在 SqlException 中,您还会收到 SQL 错误代码或其他内容。
最好的方法可能是在你的数据库中有一个单独的表,它基本上映射那些可能发生在更有意义的、面向用户的消息中的技术 SQL 错误。例如,如果您的 SQL 错误显示“fk 违反 blablabaal”之类的内容,则您可以在“UserErrorTable”中有一个条目,将其映射到一条用户消息,说“无法删除用户(this.and.that),很可能是因为 .. ......(他仍然是一个团队的成员)”或其他什么。
然后,您可以尝试在您的业务层中捕获那些 SqlExceptions,将这些技术信息转换为您的用户的自定义异常,放入用户友好的消息,并将技术异常粘贴到您的自定义异常类型的 .InnerException 中:
public class UserFriendlyException : Exception
{
public string UserErrorMessage { get; set; }
public UserFriendlyException(string message, SqlException exc) : base(message, exc)
{
UserErrorMessage = MapTechnicalExecptionToUserMessage(exc);
}
}
Run Code Online (Sandbox Code Playgroud)
马克
错误消息并不等同于异常。错误消息应该为用户提供丰富的信息,并且最重要的是可操作的。我建议您阅读用户体验指南中有关错误消息的一些指南。Apple 在编写良好的警报消息方面也有很好的通用指南。
您会立即注意到大多数(如果不是全部)SQL 错误都不是好的最终用户消息。“约束 FKXF#455 违规”- 最终用户的错误。“文件组已满”- 最终用户的错误。“僵局”——一样。好的应用程序的作用是区分用户的角色。管理员需要看到这些错误,而不是最终用户。因此,应用程序始终记录完整的 SQL 错误及其所有详细信息,最终通知管理员,然后向用户显示不同的错误,例如“发生系统错误,已通知管理员”。
如果最终用户可以对 SQL 错误采取行动,那么您可以向他显示一条错误消息,指示他如何解决问题(例如,更改输入中的发票日期以满足约束)。但即使在这种情况下,大多数时候您也不应该直接向用户显示 SQL 错误(您已经看到了为什么不这样做的一个很好的理由:本地化)。我知道这会给您的开发团队带来更大的工作量。您必须从您可能捕获的众多错误中了解每种情况下用户可操作的错误。这是众所周知的,这正是为什么优秀的程序经理知道大约 80% 的代码正在处理错误情况,以及为什么应用程序“完成”通常意味着已完成 20%。这就是优秀应用程序与普通应用程序的区别:出现问题时它们的行为方式。
我的建议是从渐进披露的原则入手。显示一条通用错误消息,指出“操作失败”。如果用户在错误消息对话框上按下“显示详细信息...”按钮,则显示更多详细信息,并显示 SqlError 集合(顺便说一句,您应该始终记录并显示SqlException.Errors的整个SqlError 集合,而不是 SqlException )。使用SqlError.Number属性在 catch 块中添加逻辑,决定用户是否可以对错误执行任何操作(决定错误是否可操作)并添加适当的信息。
不幸的是没有仙尘。您正在触及项目中最困难的部分。
| 归档时间: |
|
| 查看次数: |
2086 次 |
| 最近记录: |