I am currently working with SQL on my C# asp.net page.
I insert a value into the Database, but then if the ID is duplicate I get this exception:
{"Violation of PRIMARY KEY constraint 'PK_Section'. Cannot insert duplicate key in object 'dbo.Section'.\r\nThe statement has been terminated."}
What I want to do is to treat the exception doing something like:
if(exception=={"Violation of PRIMARY KEY constraint 'PK_Section'. Cannot insert duplicate key in object 'dbo.Section'.\r\nThe statement has been terminated."})
//update values instead of insert
My problem is that I can't compare exception(which is a string) with that long "string" that I get from trying to duplicate the IDs.
Is there anyway that I can compare this so that I can properly work on a solution to this error?
You should catch the SqlException (which will probably be the InnerException of your exception) and check its Number property to identify the exception.
See http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception.number.aspx
I would use a try catch block to check for a SqlException. Something like this:
private bool SaveDocument()
{
bool saved = false;
try
{
Save();
saved = true;
}
catch (Exception ex)
{
string errorTitle = Resources.SaveErrorCaption;
string errorText = Resources.SaveErrorText;
Exception initialEx = ex;
while (ex.InnerException != null)
{
if (ex.InnerException is SqlException)
{
int errorNo = ((SqlException)ex.InnerException).Number;
if (errorNo == 2627)
{
errorTitle = Resources.DuplicateEntryErrorTitle;
errorText = Resources.DuplicateEntryErrorMessage;
}
}
ex = ex.InnerException;
}
MsgBox.Show(errorTitle, errorText,
string.Format("{0}{1}StackTrace:{1}{2}", initialEx.Message, Environment.NewLine, initialEx.StackTrace),
MsgBoxButtons.OK, MsgBoxImage.Error);
}
return saved;
}
Related
I have a stored procedure to insert data into a table.
This is how I call the stored procedure from the controller method:
var insert_query = entities.Database.SqlQuery<Call_Info>("exec [dbo].[insert_call_info] #call_id, #user_id, #call_arrive, #call_end, #info",
new SqlParameter("call_id", call_id),
new SqlParameter("user_id", u_id),
new SqlParameter("call_arrive", call_arrive),
new SqlParameter("call_end", call_end),
new SqlParameter("info", info)
).ToList();
var jsonResult = JsonConvert.SerializeObject(insert_query); // <-- using Newtonsoft.Json
return Json(jsonResult);
If I insert a call_id value that is already stored in the table, I get this error, which is correct:
Message": "An error has occurred
Violation of UNIQUE KEY constraint 'UQ__Call_Inf__427DCE6904E3DF9B'. Cannot insert duplicate key in object 'dbo.Call_Info'. The duplicate key value is (91390).
Is there a way to catch this error in the controller?
Definitely.
You can use a try catch block to capture the SqlException
try
{
//SQL query
}
catch(SqlException ex)
{
foreach(SqlError err in ex.Errors)
{
if((err.Number == 2601) //unique nonclustered index
|| (err.Number == 2627)) //unique constraint
//handle it
}
}
Use
catch(SqlException ex)
{
}
How to catch a specific SqlException error?
I have a simple entity insert as follows:
using (var db = new MyContext())
{
var item = new Artist();
TryUpdateModel(item);
if (ModelState.IsValid)
{
db.Artist.Add(item);
try
{
db.SaveChanges();
gvArtist.DataBind();
gvArtist.Visible = true;
}
catch (Exception e)
{
Master.Warning = e.InnerException.InnerException.Message;
}
}
}
e.Message and e.InnerException.Message both equate to:
"An error occurred while updating the entries. See the inner exception for details."
But, e.InnerException.InnerException.Message gives the exception I'm looking for, which is:
"Violation of UNIQUE KEY constraint 'UQ_artist_Cuid'. Cannot insert duplicate key in object 'dbo.artist'. The duplicate key value is (11). The statement has been terminated."
I'm worried about missing other exceptions, or causing an exception if I just keep
Master.Warning = e.InnerException.InnerException.Message;
in play.
Your fears are completely founded. Something like this is what you're looking for.
catch (Exception ex)
{
while (ex.InnerException != null)
{
ex = ex.InnerException;
}
Master.Message = ex.Message;
}
The reason for the errors being varying levels deep is that the errors can occur in different sections of code, and they may bubble up through a varying number of methods that wrap them inside other exceptions. You can't plan for them to come from a specific level.
I am trying to create a transaction like so:
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required,
options))
{
try
{
dbContext.MyTable.PartnerId = someGuid;
dbContext.SaveChanges();
scope.Complete();
dbContext.AcceptAllChanges()
}
catch (Exception ex)
{
log.LogMessageToFile("Exception - ExceptionType: " +
ex.GetType().ToString() + "Exception Messsage: " + ex.Message);
}
}
I know if I try to insert an item manully in sql with a duplicate in a specific column, I get the following error from sql:
Cannot insert duplicate key row in object 'dbo.MyTable' with unique index 'idx_PartnerId_notnull'. The duplicate key value is (7b072640-ca81-4513-a425-02bb3394dfad).
How can I programatically catch this exception specifically, so I can act upon it.
This is the constraint I put on my column:
CREATE UNIQUE NONCLUSTERED INDEX idx_yourcolumn_notnull
ON YourTable(yourcolumn)
WHERE yourcolumn IS NOT NULL;
Try this:
try {
}
catch (SqlException sqlEx) {
}
catch (Exception ex) {
}
SQL errors and warnings that happen on the server side are caught in this exception.
Read about it here:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception(v=vs.110).aspx
The above answer would allow you to catch the SqlException, but you would need to further refine the handling within the 'SqlException' catch block if you only want to inform the user of a particular error. The SqlException class has a property of 'ErrorCode' from which you can derive the actual error being produced by the server. Try doing something like below:
try
{
}
catch (SqlException sqlEx)
{
if(sqlEx.ErrorCode == 2601)
{
handleDuplicateKeyException();
}
}
2601 is the actual error code produced by SQL Server for you particular error. For a full list just run the SQL:
SELECT * FROM sys.messages
Use SqlException's number property.
For duplicate error the number is 2601.
catch (SqlException e)
{
switch (e.Number)
{
case 2601:
// Do something.
break;
default:
throw;
}
}
List of error codes
SELECT * FROM sysmessages
You can catch it by its type:
try
{
// ...
}
catch (SpecialException ex)
{
}
catch (Exception ex)
{
}
EDIT: According to Ivan G's answer, you will get an SqlException, which has an error ErrorCode property that probably specific. So you have to check the error code for this type of error.
you can check exception text or it's other parameters when it is thrown, so then you can act like you wan conditionally
like :
catch(SqlException ex)
{
if(ex.Message.Contains("Cannot insert duplicate key row in object"))
{
}
}
or exception number like
catch(SqlException ex)
{
switch (ex.Number)
{
case : someNumber:
{
//..do something
break...;
}
}
}
Which Error Code is return in SQL Server when inserting duplicate value in primary key column (table)
try
{
dataAdapterObj = new SqlDataAdapter(selectString, conObj);
return true;
}
catch (Exception e)
{
MessageBox.Show("Exception is : " + e.ToString());
return false;
}
The error code is 2627 (Violation of PRIMARY KEY constraint)
try
{
// do insert
}
catch (SqlException e)
{
if (e.Number == 2627)
//do something
}
The error code you're looking for is 2601. Use the SqlException.Number property
catch (SqlException e)
{
MessageBox.Show(String.Format("Exception is {0} - {1}", e.Number, e.Message));
}
2601
Example: Cannot insert duplicate key row in object 'my_table_name' with unique index 'my_index_name'.
2627
Example: Violation of PRIMARY KEY constraint 'my_constraint_name'. Cannot insert duplicate key in object 'my_table_name'.
Source: https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/cc645728(v=sql.105)
I need to see an errorcode produced by a SqlException - however, I can't get one to fire. I use NHibernate and have a SQL UNIQUE CONSTRAINT setup on my table. When that constraint is violated, I need to catch the error code and produce a user-friendly message based off of that. Here is a sample of my try/catch:
using (var txn = NHibernateSession.Current.BeginTransaction()) {
try {
Session["Report"] = report;
_reportRepository.SaveOrUpdate(report);
txn.Commit();
Fetch(null, report.ReportId, string.Empty);
} catch (SqlException sqlE) {
var test = sqlE.ErrorCode;
ModelState.AddModelError("name", Constants.ErrorMessages.InvalidReportName);
return Fetch(report, report.ReportId, true.ToString());
} catch (InvalidStateException ex) {
txn.Rollback();
ModelState.AddModelErrorsFrom(ex, "report.");
} catch (Exception e) {
txn.Rollback();
ModelState.AddModelError(String.Empty, Constants.ErrorMessages.GeneralSaving);
}
}
Please pardon my ignorance.
Check this out which illustrates how to catch a GenericADOException and look at the InnerException property:
catch (GenericADOException ex)
{
txn.Rollback();
var sql = ex.InnerException as SqlException;
if (sql != null && sql.Number == 2601)
{
// Here's where to handle the unique constraint violation
}
...
}
Instead of catching a SqlException directly in your controller, I'd set up a SQLExceptionConverter to translate it to a more meaningful exception.