Catching specific exception
How can I catch specific exception using c# ?
In my database there is unique index on some columns. when user inserts duplicate record this exception has been throw :Cannot insert duplicate key row in object 'dbo.BillIdentity' with unique index 'IX_BillIdentity'. The statement has been terminated.
How can I catch this exception?
Currently I am checking using this code : catch (Exception ex) {
if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
string ScriptKey = "$(function() {ShowMessage('Error');});";
ScriptM开发者_如何学Goanager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
}
}
I think its bad smell code.
Is there any better way?Handle SqlException
only in this case.
[Edit]
To check duplicate key exception in MS SQL server:
try
{
// try to insert
}
catch (SqlException exception)
{
if (exception.Number == 2601) // Cannot insert duplicate key row in object error
{
// handle duplicate key error
return;
}
else
throw; // throw exception if this exception is unexpected
}
Edit: Where 2601 come from?
select *
from sys.messages
where text like 'Cannot insert duplicate key%'
Returns:
message_id language_id severity is_event_logged text
----------- ----------- -------- --------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2601 1033 14 0 Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.
Using exception.Number
and referencing sys.messages view you can handle any specific MS SQL exception.
You haven't shown the type of exception which is thrown, but you can catch that specific exception type. For example:
catch (DuplicateKeyException e) {
...
}
It's possible that there won't be a specific exception type for just this error - but if you have to catch something fairly general like SqlException
you can then look for more details within the class itself. For example in SqlException
there's an Errors
property where you can look at more detailed information about each of the (possibly multiple) errors at the database side. Each SqlError
then has a Number
property which will give the type of error. You can always fall back to the message if you absolutely have to, but you then need to be aware of the possibility of the message changing for different cultures etc.
Note that if you're not really handling the exception, you should probably rethrow it:
catch (SqlException e) {
if (CheckWeCanHandle(e)) {
// Mess with the ScriptManager or whatever
} else {
throw;
}
}
I've just picked up a project where someone went down this route:
Catch ex As SqlException
Select Case ex.Number
Case 2601
...
Note the following (from sys.messages in SQL Server):
2601 - Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'.
But what about this..?
2627 - Violation of %ls constraint '%.*ls'. Cannot insert duplicate key in object '%.*ls'."
I just spent some time tracking down exactly this problem.
And what if we change DB provider? Presumably 2601 is not absolutely universal... This stinks, IMO. And if you are (were) dealing with this in your presentation layer, I think there are bigger questions to ask.
If this must be the mechanism of choice, bury it deep, deep down in the DAL and let a custom Exception percolate up. That way, changes to the data store (or, ideally, this mechanism) have a much more limited area of effect and you can handle the case consistently without any questions in the presentation layer.
I'm currently leaning towards doing a light-weight SELECT for an ID on an open connection and avoiding the exception altogether.
As documented here, you can use exception filters. Example:
try
{ /* your code here */ }
catch (SqlException sqlex) when (sqlex.Number == 2627)
{ /* handle the exception */ }
Working code for filter only duplicate primary key violation exception
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
try {
abc...
} catch (DbUpdateException ex) {
if (ex.InnerException.InnerException is SqlException sqlEx && sqlEx.Number == 2601) {
return ex.ToString();
} else {
throw;
}
}
Note fine detail :- ex.InnerException.InnerException
not ex.InnerException
You could only catch the SqlException for starters
catch (SqlException ex) {
if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
string ScriptKey = "$(function() {ShowMessage('Error');});";
ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
}
}
精彩评论