有没有办法在约束违规时提供用户友好的错误消息

时间:2011-05-20 07:29:15

标签: oracle user-friendly

说我有专栏Gender和约束CHECK( Gender IN ('F', 'M', 'OTHER')) 如果我不小心忘记在客户端处理这个问题,用户会看到像是一样的smth ORA-02290: check constraint (SYS_C099871244) violated
对于用户,维护或调试的开发人员也不是很有帮助

是否可以提供开发人员定义的消息,如(伪)Java的 assert Gender IN (0,1):'Gender must be F or M'

我能想到的唯一方法是将约束移动到BEFORE UPDATE或INSERT触发器,并在失败时执行Raise_Application_Error( code, my_message )。但我不喜欢它

修改 具体原因清单,见评论中 我真的很想让逻辑尽可能接近数据 2.对于最终用户,Raise_Application_Error消息与应用程序消息无法区分 3.即使访问数据绕过应用程序,开发人员也会看到好消息 4.将约束移动到触发器是丑陋的(是吗?),所以我必须找到与Raise_Application_Error不同的smth

EDIT2 1.5年后,在我离开与数据库相关的工作之后,它终于发生在我身上,我真的不喜欢这个 - 代码重复 。我必须在服务器和客户端重复完全相同的逻辑。最有可能的是,有两种不同的语言。并保持同步。这太丑了。

虽然答案清楚地表明,但我无能为力。所以现在是我成为好公民并最终接受答案的时候了(对不起,只是忘记了这一点)。

4 个答案:

答案 0 :(得分:9)

约束是数据库用来保护自己免受错误的应用程序的影响,而不是来自用户。

这意味着应用程序应捕获约束违规,并清除可能以呈现给用户。我认为一个没有这样做的应用程序会以某种方式存在缺陷。

我说'可能',因为你的申请(至少在这种情况下)应该永远不会发生这种情况。它几乎可以肯定是使用下拉限制选择控件来做类似的事情。如果它使用组合框或(震惊,恐怖)自由格式文本输入字段,则需要重新定义。

这意味着违规行为永远不会发生,除非应用程序和约束在某些时候不同步。但是,在客户将肮脏的小手放在应用程序之前很久就应该在测试中发现这一点。


要回答您的实际问题,无法更改Oracle发出的用于违反约束的消息。您可以做的最好的事情是智能地命名您的约束,以便它对最终用户有意义。

但我仍然坚持认为,向用户呈现问题是应用层的责任,而不是数据库层。

答案 1 :(得分:4)

如果您正在寻找一种方法来告诉Oracle始终用另一条消息“ORA-20001:性别必须是F或M”替换异常消息“ORA-02290:检查约束(SYS_C099871244)”,那么答案是:不,它无法完成。

您可以做的是提供开发人员可以在其代码中使用的解决方案:

...
begin
    insert into emp (empno, gender) values (p_empno, p_gender);
exception
    when others then
       error_pkg.handle_exception;
end;

error_pkg.handle_exception过程将解析Oracle异常消息并提取约束的名称(如果它是约束违规)并在交叉引用表中查找该约束名称以获取所需的消息,然后使用{ {1}} r使用新消息重新引发异常。

我认为Oracle可以提供这样的包和表作为标准,但也许因为在实践中对系统中的错误处理有许多不同的要求,所以它被认为通常不够用。

答案 2 :(得分:3)

是否将约束提升到客户端或者通过支持登录到(潜在)分析的文件中,您应该有一个更有用的消息。

如果您为约束命名,则会更有帮助。

我会选择像

这样的东西
ALTER TABLE blah ADD CONSTRAINT blah_gender_ck CHECK ( Gender IN ('F', 'M', 'OTHER'));

答案 3 :(得分:3)

简而言之:
没有办法捕获我知道的自定义处理的oracle错误。不过,我认为你不应该尝试这样做。


长版:
你的理由背后的意图是好的,但是......

  

我真的希望逻辑尽可能接近数据

逻辑应该尽可能接近数据,这是真的;但是这不合格 - 这不是逻辑,这是识别已经定义的逻辑的例外的代码的表示,并且表示不应该与数据或逻辑层混合(错误消息的域跨越系统的每个部分;从客户端到服务器端,还要考虑翻译,一致的更新,更容易的管理和消息概述等等。)

  

对于最终用户,Raise_Application_Error消息是   与申请无法区分   消息

是的,但反过来也是有效的,因此不是特别相关 - 如果你有DB错误代码的中央存储库,应用程序错误代码和错误处理将处理它然后它是无关的(对于最终用户)哪个层是提供错误消息。此外,从长远来看,不清楚它会为你节省任何工作。

  

即使访问数据绕过,开发人员也会看到好消息   应用

这是真的,对于直接访问DB的开发人员来说,会有更好的错误消息。这里仍然有一些注释 - 在复杂的系统中,不应允许绕过应用层(即使是开发人员);如果允许,你会希望开发人员知道在哪里查找来自约束名称的错误消息(错误代码和消息的中央存储库应该/将在同一个数据库中维护)

  

将约束移动到触发器是很难看的   (是吗?),所以我必须找到smth   与Raise_Application_Error不同

在某种意义上它是丑陋的,它是演示文稿,不应该在DDL中。此外,如果通过触发器完成(不确定它有多大,也不是多么优雅),它会导致不合理的(?)性能损失。

注意:总而言之,我确实认为有可能挂钩到DBMS错误处理是一个很好的功能。

但是,错误处理和错误消息处理具有以下属性

  • 需要可维护(理论上,这可以通过在信息模式中存储自定义错误消息来干净地完成,但SQL标准没有指定,所以这纯粹是理论上的注释 - 实际上你必须拥有自己的表为此目的)

,更重要的是

  • 错误消息处理上下文敏感(从数据客户端的角度来看,错误处理程序最为通知 - 有时相同的错误代码可能需要不同的呈现方式,不同的消息)