Entity Framework Throw Exception for Insert Duplicate error - c#

I am using Entity Framework and Telerik RadGrid. I have a table with a constraint which throws an exception if a product with a duplicate name is tried as an insert. I am trying to catch the exception in my business layer and it seems to run through the catch block fine but I get an error from the Telerik RadScriptManager
"Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: Exception has been thrown by the target of an invocation."
instead of the Jquery popup that I am expecting with the message "Duplicate Product" Does anyone know what I am doing wrong? does the exception need to behandled in my DAL? but I dont think i should throw BusinessRuleExceptions from somewhere besides the BLL. I have posted the Insert function in my BL class below, if anyone has an idea what might be causing the Jscript error, please let me know, thanks!!
Edit
The Object Data Source TypeName is tied to the Business layer ProductBL
Product BL function Insert_Product is being called from my ObjectDataSource as the Insert function. In the Product.cs code behind class I have a function for Inserting Products where I am passing the product Name (see below), this function has a try catch bloeck..should I be throwing the exception here? I thought it would be right to throw the BusinessRulException in the Business Layer.
Product.CS class (Object Data Source Insert command)
protected void ODSProducts_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
try
{
TextBox txtProductName = (TextBox)ProductsGrid.MasterTableView.GetInsertItem().FindControl("txtProductName");
((ACME.DAL.Product)e.InputParameters[0]).Product.product_name = txtProductName.Text;
}
catch (Exception ex)
{
HTMLError.HtmlError.LogHtmlError(ex, Application["ErrorLog"].ToString());
throw;
}
}
ProductsBL.CS
public void Insert_Product(Product product)
{
try
{
repository.Insert_Product(product);
}
catch (Exception ex)
{
if (ex.GetType().Name == "UpdateException")
{
throw new BusinessRuleException("Duplicate Product");
}
}
}
Product.DAL
public void InsertProduct(Product product)
{
context.Products.AddObject(product);
context.SaveChanges();
}

You will want to tap into the RadGrid_ItemInserted event. There the event arg should have a reference to the exception thrown, and you can mark that you handled the exception so it doesn't bubble up to the user.
That's if you are letting the ODS do the full insert, and not inserting manually.

ok I figured this out after wasting too many hours on this. It seems like Telerik doesnt like me throwing the Business rule exception from the Business Layer class. So I ended up handling the exception instead in the codebehind in the object data source_Inserted event. This is what I did to display the error in a RadAlertWindow from the event.
enter code here
protected void ODSProducts_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
if (((e.Exception.InnerException).InnerException).Message.Contains("Cannot insert duplicate key row"))
{
RadWindowManager.RadAlert("Duplicate Product, Enter a new Product", 330, 100, "Insert Error", "");
e.ExceptionHandled = true;
}
}
}
I dont like checking the .InnerException.Message.Contains bit but thats the only way I knew how to make sure if the exception was SQL throwing duplicate error on the unique constraint on the field. If someone knows of a more elegant way to do this please share. Hope this helps someone else as well.

Related

Linq to SQL - SubmitChanges() - Check if insert was successful

I have following code -
public bool InsertUser(params)
{
User objUser = new User(params);
objDataContext.Users.InsertOnSubmit(objUser);
objDataContext.SubmitChanges();
return objUser.Id >= 0;
}
Calling method -
if (!_database.InsertUser(params))
{
//WriteErrorMessage
}
As I understand from various posts that if we want to know whether an insert was successful or not, we should check if any exception is being thrown.
However above code is relying on whether newly inserted Id is >=0 or not.
Can please guide -
If I should change above code and add a try-catch instead?
Is there any possible scenario where no error is thrown by SubmitChanges() but newly inserted Id <= 0 ?
Thank you!
If I should change above code and add a try-catch instead?
No, don't do that as in that case you will not be able to get the exact reason of failure. If you catch it then the information of failure will be lost and will not propogate to the user.
However if you think that giving exception to the user is not a good idea and you need to catch it then simply place it inside the try catch like this:
public bool SubmitChanges()
{
try{
//your code
db.SubmitChanges();
return true;
}
catch(Exception e)
{
// some code to catch exception
return false;
}
}
Is there any possible scenario where no error is thrown by SubmitChanges() but newly inserted Id <= 0 ?
If you are getting the value >=0, then there is no point to worry about this.
You can also use the GetChangeSet like this:
Gets the modified objects tracked by DataContext.
ChangeSet cs = db.GetChangeSet();
Console.Write("Changes: {0}", cs);
if your code execute the line objDataContext.SubmitChanges(); and comes on return objUser.Id >= 0; your insert will be successfull. you don't need to worry after that. let sql server and your compiler take care of the rest
Yes can use try catch to efficiently catch the error and display appropriate messages.

SqlException not passing a value

I have a handler class file, a default page and a master page.
The default page instantiates an instance of the handler class, and the handler then does all the communication with the database.
The master page contains a label that is supposed to display error outputs, passed to it from the handler via the default page. This is done via the following:
Handler:
catch (SqlException e)
{
errorString = e.ToString();
}
Default.aspx.cs:
errorString = handler.errorString;
((SiteMaster)Master).getErrorLabel.Text = errorString;
Site.Master.cs:
public Label getErrorLabel
{
get { return this.errorLabel; }
}
When I pass a value that doesn't match any record in my database, the errorString continues to hold null. Am I doing something wrong?
edit: I have also tried e.Message and e.Message.ToString() without success
Your catch() specifies an SQLException class. If the exception thrown is not of that type, then the actual exception is not handled. Try changing that to the base Exception class and see what you get. It's probably an error being thrown from somewhere else in the code.

How to catch multiple exceptions on SaveChanges() or is it possible?

I get an XML file(from an infopath form), create an object and insert that object into the DB. Im using a C# webservice to do this parsing and it returns true if successful and currently it returns the exception message if the SaveChanges() fails. The main exceptions I'd like to return are the DbEntityValidationExceptions as I'll handle other exceptions differently. Some of the columns have max lengths so is the field exceeds that I want to return the field name that they need to edit. Can I catch all the DbEntityValidationException for all fields that failed or does entity only throw the first exception and then rollback the transaction? With 200 fields it'd be nice to tell the user which fields they need to change versus the first field and then continue to fail as they fix the single exception each time.
If it is not possible my proposed solution below is irrelevant and should be removed. If it is possible to return all the Exceptions, what am I doing wrong?
exceptionList = new List<string>();
try
{
db.SaveChanges();
}
catch (Exception ex)
{
if (ex.GetType() == new DbEntityValidationException().GetType())
{
DbEntityValidationException eValidEx = (DbEntityValidationException) ex;
foreach (DbEntityValidationResult vResult in eValidEx.EntityValidationErrors)
{
foreach (DbValidationError vError in vResult.ValidationErrors)
{
exceptionList.Add(vError.ErrorMessage);
}
}
result = false;
}
else
{
exceptionList.Add("Unknown. " + ex.Message);
}
}
You need custom exception which inherit Exception. In this exception you have property for example Errors. This property will be message collection.
When you are trying to save changes, you should know what kind of fields you are expecting. You should define in other class boundaries of the fields(example Price->decimal, mandatory, maxValue and so on) On save you should check the boundaries if one of them is not true you should add message string in Errors of the custom exception(example Price is not decimal field)
On the end if the Errors.Count > 0 thorw the CustomException. You should override the message property in the CustomException -> loop all the Errors and return the text of all of them. At the end you need only customException.Message and you will have all the problems shown to the user.
I Hope this helps.
So when you catch an exception like that, you'll only catch the first exception. Java doesn't let you keep going on when you have a bunch of Exceptions and to catch all of them.
What you could do is put the entire thing in a while loop that keeps going until you've saved all of the changes. Make sure in the try{} block that you iterate through each field instead of just trying the first field again and again.

How to determine the correct constraint violation on SQLite UpdateException?

I have the following problem qith my local SQLite database. I'm trying to update the data stored via a synchronisation-process with an online SQL-Server database.
While there is no problem with the synchonization I often encounter errors when trying to update the local values.
E.g. there can be an violation with existing Primary-Key-Constraints on each table. On the other hand there could also be a violation of the Unique-Key on a concrete table.
My question is how to figure out which type of error occured.
I catch the database update or insert like
catch(UpdateException ue)
{
HandleUpdateException(ue);
}
The handle method is as follows:
private void HandleUpdateException(UpdateException e)
{
// get inner exception as SQLiteException
var innerException = e.InnerException as SQLiteException;
if(innerException != null)
{
switch(innerException.ErrorCode)
{
case SQLiteError.Constraint:
// handle constraint-error here
break;
default:
// log error
break;
}
}
}
How do I now which error occured? It's important to know because the handling of PK-violation is completely other than a UK-violation.
I could try to make
if(e.Message.Contains("unique")) // ...
or
if(e.Message.Contains("foreign")) // ...
but I don't like to check with "magic" strings for the kind of error.
So any help would be appreciated.

Programmatically suppressing exceptions in C#

I have the following try-catch statement and I do not want to not throw the exception if the message property contains 'My error' in the text.
How can I programmatcially accomplish this? Also, would this be considered code-smell?
try
{
}
catch(Exception e)
{
if(e.Messages.Contains("My error"))
{
//want to display a friendly message and suppress the exception
}
else
{
throw e;
}
}
You shouldn't catch errors based on the error test. You should make your own exception class that extends exception:
class MyErrorException : Exception { }
and throw and catch those. (Excuse my syntax if it's wrong, I haven't done C# in a while).
That being said, throwing and catching your own Exceptions instead of propagating them is perfectly normal, and it is how you actually should do exception handling.
You should be catching the specific exception you're looking for. Quite frankly, that code is shocking. You should have something like ...
public class MyCoolException : Exception {
public MyCoolException(string msg) : base(msg) {}
}
public void MyCoolMethod() {
// if bad things happen
throw new MyCoolException("You did something wrong!");
}
Then later in your code you can use it like ...
try {
MyCoolMethod();
} catch (MyCoolException e) {
// do some stuff
}
Your code creates maintainability issues because a simple text change can have strange side effects. You can have your own exception class which inherits from System.Exception. Then instead of having an if you could do the following:
try
{
}
catch(MyException myException) //or just catch(MyException)
{
//display a friendly message
}
also you don't want to do throw e because it doesn't preserver the Stack, just throw; will do.
When I throw Exception rather than a derived class I always mean a failed assertion. I don't like failing out the backend because we are still able to receive a request (just not that one again). If we're really toast it will just error out on the next request anyway.
When the back end needs to generate an error message I have a ErrorMessage class that inherits from Exception and takes ErrorMessage and ErrorMessageTitle as constructor arguments.

Categories