有没有办法在违反约束时给出用户友好的错误消息
假设我有列 Gender
和约束 CHECK( Gender IN ('F', 'M', 'OTHER'))
。
如果我不小心忘记在客户端处理这个问题,用户将看到类似ORA-02290: 违反检查约束 (SYS_C099871244)
这对用户和维护或调试的开发人员来说都不是很有帮助
有没有办法提供开发人员定义的消息,例如(伪)Java的assert Gender IN (0,1):'Gender must be F or M'
我能想到的唯一方法是将约束移至 BEFORE UPDATE OR INSERT 触发器,并在失败时执行 Raise_Application_Error (代码,my_message)
。但我不喜欢它
编辑 具体原因列表,如评论中
1. 我真的很喜欢让逻辑尽可能接近数据
2. 对于最终用户而言,Raise_Application_Error 消息与应用程序消息无法区分
3.即使绕过应用程序访问数据,开发人员也会看到不错的消息
4.将约束移动到触发器很丑陋(是吗?),所以我必须找到与 Raise_Application_Error 不同的东西
EDIT2 1.5 年后,在我离开与数据库相关的工作后,我终于意识到,我真正不喜欢这个 - 代码重复 。我必须在服务器和客户端上重复完全相同的逻辑。最有可能的是,用两种不同的语言。并使它们保持同步。这太丑了。
尽管答案清楚地表明,我对此无能为力。所以现在是我成为好公民并最终接受答案的时候了(抱歉,只是忘记了这一点)。
Say I have column Gender
and constraint CHECK( Gender IN ('F', 'M', 'OTHER'))
.
If I accidentally forgot to handle this on client side, user will see smth likeORA-02290: check constraint (SYS_C099871244) violated
which is not very helpful nor for user, nor for developer who maintains or debug
Is there way to provide developer-defined message like (pseudo)Java'sassert Gender IN (0,1):'Gender must be F or M'
The only way I can think of is to move constraints to the BEFORE UPDATE OR INSERT trigger and on failure do Raise_Application_Error( code, my_message )
. But I don't like it
EDIT
List of specific reasons, as per in the comments
1. I really like to keep logic as close to data as possible
2. For end user Raise_Application_Error message is indistinguishable from application message
3. Developers will see nice message, even if access data bypassing application
4. moving constraints to triggers is ugly (is it?), so I have to find smth different from Raise_Application_Error
EDIT2
1,5 years later, and after I've left db-related job, it has finally occured to me, what I really don't like about this - code duplication. I have to repeat exactly same logic on server and on client side. Most likely, in 2 different languages. And keep them in sync. This is just ugly.
Though as answers clearly indicate, there is nothing I can about this. So it's time for me to be good citizen and finally accept an answer (sorry, just forgot about that).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
约束是数据库用来保护自己免受错误应用程序,的影响,而不是来自用户的影响。
这意味着应用程序应该捕获约束违规,并可能进行清理以呈现给用户。我认为没有这样做的应用程序在某种程度上是有缺陷的。
我说“可能”是因为您的应用程序(至少对于这种情况)永远不会看到这种情况发生。几乎可以肯定,它应该使用下拉式有限选择控件来实现类似的功能。如果它使用组合框或(震惊,恐怖)自由格式的文本输入字段,则需要重新定义。
这意味着违规永远不会发生,除非应用程序和约束在某个时刻不同步。但是,早在客户接触您的应用程序之前,就应该在测试中发现这一点。
为了回答您的实际问题,Oracle 发出的有关约束违规的消息无法更改。您能做的最好的事情就是明智地命名您的约束,以便最终用户能够理解。
但我仍然认为向用户呈现问题是应用程序层的责任,而不是数据库层的责任。
Constraints are what databases use to protect themselves from errant applications, not from users.
That means that constraint violations should be captured by the application and possibly cleaned up for presentation to the user. I'd consider an application which didn't do that to be deficient in some manner.
I say 'possibly' since your application (at least for this case) should never see that happen. It should almost certainly be using a drop down limited-choice control for something like that. If it used a combo-box or (shock, horror) a free-format text entry field, it would need to be redefined.
That would mean that the violation would never occur unless, of course, the application and the constraint get out of sync at some point. But that's something that should be caught in testing, long before a customer ever gets their grubby little hands on your application.
To answer your actual question, the messages that come out of Oracle for constraint violations cannot be changed. The best you can do is to name your constraints intelligently so that it may make sense to an end user.
But I still maintain that this presentation of problems to a user is a responsibility of the application layer, not the database layer.
如果您正在寻找一种方法来告诉 Oracle 始终将异常消息“ORA-02290:违反检查约束 (SYS_C099871244)”替换为另一条消息(例如“ORA-20001:性别必须是 F 或 M”),那么答案是:不,这是不可能的。
您可以做的是提供一个可供开发人员在其代码中使用的解决方案,如下所示:
error_pkg.handle_exception
过程将解析 Oracle 异常消息并提取约束的名称(如果是)约束违规)并在交叉引用表中查找该约束名称以获取所需的消息,然后使用 raise_application_error 使用新消息重新引发异常。我想Oracle可以提供像这样的包和表作为标准,但也许由于在实践中系统中的错误处理有许多不同的要求,所以它通常被认为不够有用。
If you are looking for a way to tell Oracle always to replace the exception message "ORA-02290: check constraint (SYS_C099871244) violated" by another message like "ORA-20001: Gender must be F or M", then the answer is: no, it can't be done.
What you can do is provide a solution that can be used by developers in their code something like this:
The
error_pkg.handle_exception
procedure would parse the Oracle exception message and extract the name of the constraint (if it was a constraint violation) and lookup that constraint name in a cross reference table to get the required message, then useraise_application_error
to re-raise the exception with the new message.I suppose Oracle could offer a package and table like this as standard, but perhaps since in practice there are many different requirements for error handling in system, it isn't considered to be generally useful enough.
简而言之:
据我所知,没有办法捕获用于自定义处理的 Oracle 错误。但我认为无论如何你都不应该尝试这样做。
长版:
你的理由背后的意图是好的,但是......
逻辑应该尽可能接近数据,这是事实;但这不符合条件 - 这不是逻辑,这是识别已定义逻辑异常的代码的表示,并且表示不应与数据或逻辑层混合(错误消息的范围涵盖从客户端到服务器端的每个部分;还要考虑翻译、一致更新、更轻松的消息管理和概述等...)
True,但反之亦然,因此不是特别相关 - 如果您有数据库错误代码、应用程序错误代码的中央存储库,并且错误处理将对其进行处理,那么哪一层出现错误是不相关的(对于最终用户)消息。此外,从长远来看,尚不清楚它是否会节省您的任何工作。
确实如此,对于直接访问数据库的开发人员来说,会有更好的错误消息。这里仍然有一些评论适用 - 在复杂的系统中,不应允许绕过应用程序层(即使对于开发人员也是如此);如果允许的话,您会期望开发人员知道在哪里从约束名称查找错误消息(错误代码和消息的中央存储库应该/将维护在同一个数据库中)
它在某种意义上是丑陋的,因为它是表现形式,不应该出现在 DDL 中。此外,如果通过触发器完成,它会导致不合理的(?)性能损失(不确定它有多大,也不知道它可以完成得有多优雅)。
注意:总而言之,我确实同意能够挂钩 DBMS 错误处理将是一个很好的功能。
然而,错误处理和错误消息处理具有以下属性
,更重要的是,
In short:
No way of catching oracle errors for custom handling that I know of. However I don't think you should be trying to do that anyway.
Long version:
The intentions behind your reasons are good, however...
Logic should be as close to data as possible, that is true; however this does not qualify - this is not logic, this is presentation of codes that identify exceptions to already defined logic, and presentation should not be mixed with data or logic layers (the domain of error messages spans over every part of the system; from client side to server side, also think about translating, consistent updates, easier management and overview of the messages, etc...)
True, but the reverse is valid as well and therefore not particularly relevant - if you have central repository of DB error codes, application error codes, and error handling will process it then it is irrelevant (for end user) which layer is presenting error messages. Also, long term, it is not clear that it would save you any work.
This is true, for developers accessing DB directly there would be nicer error messages. Still a few comments apply here - in complex systems bypassing the application layer should not be allowed (even for developers); if that would be allowed you would expect devs to know where to look up the error messages from the constraint names (central repository of error codes and messages should/would be maintained in the same db)
It is ugly in a sense that it is presentation and should not be in DDL. Also, it incurs unjustified(?) performance penalties if done through triggers (not sure how big, nor how elegant it could be done).
Note: All in all I do agree that it would be a nice feature to have possibility to hook into DBMS error handling.
However, error handling and error message processing has following properties
and, even more importantly
无论约束是向客户端提出还是记录在文件中以供支持人员进行(潜在)分析,您都应该获得更有用的消息。
如果你命名你的约束,它会变得更有帮助。
我会去做类似的事情
Whether the constraint gets raised to the client or logged in a file for (potential) analysis by support, you should have a more useful message.
If you name your constraint it gets more helpful.
I'd go for something like