Does anyone have a simple way of handling this exception when updating a record to one that already exists in the database?
Try this:
catch (UpdateException ex)
{
SqlException innerException = ex.InnerException as SqlException;
if (innerException != null && innerException.Number == ??????)
{
//Place you exception code handling here..
}
else
{
throw; //(bubble up)
}
}
This is a simple solution, but you may have issues in the future should the error number change which is unlikely).
Related
For example, we have simple action method to show any book with proper id:
public ActionResult GetBook(int id) // id = 123456789
{
var book = dataManager.Books.GetBookById(id); // == null
logger.Info("Getting book with id " + book.Id);
return View(book);
}
If id parameter is not valid we get 500 error because there is no book with that id.
We have to handle this situation manually if we need to throw 404 error, like this:
if (book == null)
{
return HttpNotFound();
}
Is it possible to switch 500-error to 404-error for all action methods somewhere in web-application (custom filter, request pipeline)?
Technically you could, by installing an error handler, rewrite any 500 Internal Server Error to a 404 Not Found in Application_Error() as explained in ASP.NET MVC 5 error handling.
However, you seem to want to let your code throw a NullReferenceException on a null book in book.Id, and turn that exception into a 404.
You really shouldn't be doing that in this case, because this will hide programming errors, because you will miss the exceptions where this happened unintentionally.
So: just do this explicitly where you do expect a null. The code you showed is exactly what you need:
if (book == null)
{
return HttpNotFound();
}
I found this helpful Bulk 301 Redirect
I test then throw a 302
try
{
------
}
catch
{
throw new HttpException(302, "not found");
}
Catch the exception in the Global.asax and look up a redirect csv file
protected void Application_Error()
{
Exception exception = Server.GetLastError();
Response.Clear();
Server.ClearError();
HttpException ex = exception as HttpException;
if (ex.GetHttpCode() == 404 || ex.GetHttpCode() == 302 || ex.GetHttpCode() == 500)
{
Redirect code in the link!
}
}
In Grails i want to catch the exception when foreign key constraint appears, this is my code
try {
instance.delete(flush:true)
flash.message = message(code : "default.deleted.message", args : [instance])
flash.level = "info"
} catch(org.springframework.dao.DataIntegrityViolationException | Exception e) {
flash.message = message(code : "default.not.deleted.message", args : [instance])
flash.level = "danger"
}
The problem is when there is a foreign key constraint, it never enters the catch block.
Any idea what exception i should add ?
Thanks,
I am using grails 2.3.5 and following code works for me
try {
user.delete(flush: true)
render "OK"
} catch (org.springframework.dao.DataIntegrityViolationException e) {
render "DataIntegrityViolationException"
} catch (Throwable v) {
render "Throwable"
}
Try this..,.
I think it is because MySQLIntegrityConstraintViolationException is thrown on update or insert not delete
Exception thrown when an attempt to insert or update data results in violation of an
integrity constraint. Note that this is not purely a relational concept; unique primary
keys are required by most database types.
Try with com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException
EDIT
Which version of Grails are you using ?
I found this issue GRAILS-9357
Can anyone point out why I get an exception when the .results point in the code is executed?
-- note the code has been edited after the quested was answered as per Tatham Oddie's comment. ---
public User Create(User user)
{
try
{
// Check if user exists
if (this.Exists(user.EmailAddress))
{
throw new Exception("User already exists");
}
else
{
var q = this._context.Client().Cypher
.Create("(n:User {f}")
.WithParam("f", "Mike")
.Return(n => n.As<User>());
return q.Results.Single();
}
}
catch (Exception e)
{
throw e;
}
}
Please do not write code like this: "(n:User {FirstName: '" + user.FirstName + "'}". It is a major security risk in your application, and a performance constraint.
Follow the example at https://github.com/Readify/Neo4jClient/wiki/cypher-examples#create-a-user which uses a parameter syntax.
It will be secure.
It will be faster.
It will work.
Got it. Syntax error. Missing bracket.
I'm trying to implement exception handling for Optimistic lock type exceptions that are thrown by Hibernate but I've encountered a strange issue. It seems I'm unable to catch any Gorm exceptions.
For example I have this code in my service:
try {
User user = User.get(1);
Thread.sleep(10000);
user.viewedAt(new Date());
user.save(flush:true);
} catch (OptimisticLockingException ex) {
log.error("Optimistic lock exception");
} catch (StaleObjectStateException ex) {
log.error("Optimistic lock exception");
}
When I hit this block with two threads, it blows up and the exception propagates to Grails' standard exception handler. The catch blocks are never invoked even though the reported exception is StaleObjectStateException.
I've noticed that I can catch the exception if I let it propagate to the controller and catch it there, but it seems I can't implement exception handling in the service which is weird.
What am I missing?
I got to the bottom of this and I'm posting it in case anyone else runs into this. The issue occurred because the try/catch block was in a transactional service. Although grails reported that the exception was thrown during the save() call, in reality it was called AFTER the entire method, when the transaction was committed.
So it seems that:
flush: true has no effect on transactional services
It's not possible to catch GORM related exceptions in transactional services, at least not without some work
I finally worked around this by manually managing the transaction myself i.e.
try {
User.withNewTransaction {
User user = User.get(id); // Must reload object
.. // do stuff
user.save(flush:true)
}
} catch (OptimisticLockingException ex) {
...
}
I hope this is of use to someone else!
I spent some time working on this problem and have written a more complete solution to handle the case of an optimistic locking exception in Grails.
Firstly, though the exception reported in the stack trace is StaleObjectStateException, the actual exception that gets thrown is HibernateOptimisticLockingFailureException (not "OptimisticLockingException"). Secondly, if you want to generalize this to handle arbitrary closures which modify domain objects, you need to rethrow exceptions thrown inside the closure.
The following static function will take an object and a closure that operates on the object, save it, and if it fails, retry again until it succeeds:
public static retryUpdate(Object o, Closure c) throws Exception {
def retVal
int retryCount = 0
while (retryCount < 5) {
try {
Model.withTransaction { status ->
retVal = c(status)
o.save()
}
return retVal
} catch (HibernateOptimisticLockingFailureException e) {
log.warn "Stale exception caught saving " + o
if (++retryCount >= 3) { // if retry has failed three times, pause before reloading
Thread.sleep(1000)
}
o.refresh()
} catch (UndeclaredThrowableException e2) {
// rethrow exceptions thrown inside transaction
throw e2.getCause()
}
}
return null
}
Model in this case is any GORM model class, doesn't matter which one. In particular it doesn't matter if it is the class of the passed-in object.
Example of use:
AnotherModelClass object = AnotherModelClass.get(id)
retryUpdate(object) {
object.setField("new value")
}
How to catch duplicate key exceptions in Grails . when trying to save existing integer for a unique column constraint, the error is generating while saving/updating a record .
Also used
try{
object.save(flush:true)
}
catch(org.springframework.dao.DataIntegrityViolationException e){
println e.message
}
catch(org.hibernate.exception.ConstraintViolationException ex){
println e.message
}
catch(Exception e){
println e.message
}
But unable to catch this issue .
23:41:13,265 ERROR [JDBCExceptionReporter:101] Duplicate entry '1' for
key 2 23:41:13,281 ERROR [AbstractFlushingEventListener:324]
Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not
execute JDBC batch update at
org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
at
org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at
org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at
org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at
org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at
org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at
org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
Could you please share the solution to solve this .
You're trying to save a record with an id that already exists.
If id is auto-generated, don't set it manually
If id is not auto-generated, set it to something else, for example max(id) + 1
surely no Exception should be thrown for constraint violation, but rather object.save() should return null? i.e.
if(object.save() == null) {
// save failed
} else {
// save succeeded
}
If you defined the uniqueness through a Grails constraint, you have to look for a ValidationException. This is thrown when object.validate() fails; Validation is done before any object.save().
try {
object.save(failOnError: true)
}
catch(ValidationException ve) {
// Do something ...
}
But remember: Any constraint violation, for any member variable can cause a ValidationException ... so you have to distinguish yourself.
Edit:
This applies, if you use the Grails 1.2 failOnError feature ...
I am looking for the same problem so maybe not a complete answer but what you can do is to force validation and look in the errors, identify the case and place the actions you want:
if(instance.validate()) {
//everything ok
} else {
instance.errors.each {
//identify the case and place actions
}
}
Also note that error is: className.propertyName.unique
Possibly it should work:
import org.springframework.dao.DuplicateKeyException
try {
domainInstance.save(flush: true)
} catch(DuplicateKeyException e) {
// ...
}