I am writing a service layer application, which interacts with database using Entity framework.
I am enclosing my individual "unit-of-work" in a using block, where I initialise my data context.
However I need to throw some exceptions, to convey database errors to applications, which are using my service application. So I am doing something like this:
using (dbcontext = new DbContext())
{
throw new Exception("Error while Saving data");
}
Can anyone confirm if this is Ok? Will Entity framework data context be disposed off correctly even after an exception is thrown?
Yes. A using block is converted to a try/finally block when compiling with disposing logic inside the finally block.
However your exception will not be thrown outside if the Dispose method throws an exception.
Yes this is correct. From MSDN:
A using statement can be exited either when the end of the using
statement is reached or if an exception is thrown and control leaves
the statement block before the end of the statement.
That being said, I would throw a more specific exception than the Exception one.
Related
I am fairly new to Entity Framework and everything has been moving smoothly, until I encountered this error. My code is attempting to save children of a parent table using SaveChanges() but I get this error:
A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext.
This message seems tied to async calls and having to use await - SaveChangesAsync(). However I am NOT calling the async version of the SaveChanges() method but still get a thread error message.
My code is fairly simple:
public void CreateRange(IList<Section> sections)
{
// Add new sections and save context.
_SqlRunnerContext.sectionsDbSet.AddRange(sections);
_SqlRunnerContext.SaveChanges(); // This line throws the error.
}
The error seems to occur when there are at least two entries in the list. Which makes me think it's the way that Entity Framework is handling the save internally.
The code that calls this method creates a new repository which in turn creates a new dao and SqlContext. Given this I wouldn't think it would be something outside of this code causing the issue. I have also tried a foreach loop and save each item individually with the same error.
If anyone could give me a suggestion or idea what to try, it would be much appreciated.
Thanks again,
Adam
Instead of deleting all records then re-inserting. I change the code to simply update if it exists and add if new. This has resolved the issue.
I have the following test code:
try
{
Product product = productService.GetProductById(1502);
product.ProductName = "TEST PRODUCT NAME";
throw new ArgumentException("");
//Do some other DB updates
//Call SaveChanges
productService.SaveChanges();
}
catch(Exception ex)
{
logService.InsertLog(LogTypeEnum.Error, "test", ex);
logService.SaveChanges();
}
The problem is that my services share a context per request (using StructureMaps HttpContextScoped). So when the failure occurs and I call logService.SaveChanges it saves the products new name. However I lose atomicity because the "other DB updates" will not be saved to the DB. What would be the correct way to implement this?
This is always going to be a problem with context per-request. In a large project I started out with context per-request too, but have gradually removed it due to problems like this.
I would suggest identifying the scenarios like this where you are likely to need to write to your DB without calling SaveChanges - if it's all limited to this log service then perhaps you should re-implement this without the dependence on the context? Alternatively you should be able to specify a custom way of creating the log service with its own context (i.e. not just having one injected by the constructor).
I'm not familiar with the Structuremap syntax so here's something from Autofac which would do the same...
builder.RegisterType<MyContext>().InstancePerRequest(); // As you have already
builder
.Register(c => new LogService(new MyContext())
.As<ILogService>().InstancePerRequest();
This would construct LogService using an explicitly created context rather than the per-request instance which would've been injected had I registered it normally.
I have a web service (built using jaxb/jaxws) that invokes a stateless EJB to store some data in the database. The data is being stored as an entity bean. The entity bean has a unique constraint applied to it via the #Column(unique = true) annotation.
When the web service attempts to save data, the transaction fails, and rightfully so. The problem is that since I am using CMP, the transaction is not committed until after the call to the stateless EJB. The end result is that I am not able to trap the exception and it is getting funneled up to the WS stack and results in an ambiguous fault containing the string: Error committing transaction:;nested exception is: weblogic.transaction.internal.AppSetRollbackOnlyException.
Is there a way to catch the exception being thrown so I can provide more information to the caller? Thank you.
Version information:
Application Server: Oracle Weblogic 10.3
Persistence Provider: Hibernate 3.2.5.ga (JPA 1.0)
JDK/JRE: 1.6_0_05 (provided by Weblogic install)
Update:
I tried to implement an EJB 3 interceptor around the method invocation and this does not appear to work.
public class TestInterceptor {
#AroundInvoke
public Object logCall(InvocationContext context) throws Exception {
System.out.println("Invoking method: " + context.getMethod().getName());
try {
return context.proceed();
} catch (Throwable t) {
System.out.println("I caught an exception: " + t.getMessage());
throw new Exception(t);
}
}
The reason I think this doesn't work is because the processing chain is such that the actual persist happens outside of the method (of course).
You could try using Bean Validation. It's nicely connected with the JPA (invoked during pre-persist, pre-update and pre-remove phases and can be used in different layers of your application.
Unfortunately, as far as I know, if a validation constraint violation occurs, the transaction is marked for rollback... I don't know how you could cope with that but one (seems nasty and untested) way I could think of is to inject a ValidatorFactory and validate the object by yourself. Perhaps then you could catch the ValidationException.
EDIT: I'm not sure if the Bean Validation was available in Java EE 5.
EDIT 2: You can create an interceptor which will catch the exception thrown by the JPA (or more precisely by the database). As the interceptor is invoked as a part of the same transaction as the EJB method you might need to explicitly invoke EntityManager#flush(-) to synchronise changes with the database.
UPDATED
Wanting some code to run with each controller, and being told to use Action Helpers or a Plugin rather than extending from a Base Controller, I decided on an Action Helper rather than Plugin, per excellent slides by #Bittarman (Ryan Mauger);
Zend Framework, getting to grips:
http://www.slideshare.net/rmauger/zend-framework-getting-to-grips
See slide 22:
Thrown Exceptions in (action helpers) Pre/Post Dispatch will stop further execution...
While it DOES stop further execution, the exception wasn't caught. I've been trying to debug this for hours but not getting anywhere.
If you run the following code, are you seeing exceptions caught or is it escaping the Error Controller?
I'm trying to figure out whether Zend Framework is NOT behaving as expected, or if I totally messed something up (more likely).
I tried to break this down into the simplest case to replicate, let me know what you see:
/* add to existing Bootstrap located here: APPLICATION_PATH/Bootstrap.php */
protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH .'/controllers/helpers');
//hooks cause action helper to autorun: http://akrabat.com/zend-framework/hooks-in-action-helpers/
$hooks = Zend_Controller_Action_HelperBroker::getStaticHelper('Test');
Zend_Controller_Action_HelperBroker::addHelper($hooks);
}
/* in: APPLICATION_PATH/controllers/helpers/Test.php */
<?php
class Zend_Controller_Action_Helper_Test extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
// you can skip next line if you don't have xdebug
//xdebug_disable();
throw new Exception('test', 404);
parent::preDispatch();
}
}
Update:
OK, I've been running this through xDebug + Eclipse... (it was either that or have fun poking my eyes out, not sure if I chose the more pleasurable experience)....and I found out something bizarre.
The preDispatch is running twice!
And on the second call, it goes to the Zend_Controller_Plugin/ErrorHandler.php
where it runs this code:
if ($this->_isInsideErrorHandlerLoop) {
$exceptions = $response->getException();
if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) {
// Exception thrown by error handler; tell the front controller to throw it
$frontController->throwExceptions(true);
throw array_pop($exceptions);
}
}
By setting throw Exceptions to true, it no longer gets caught. And I suspect this is to save a loop from occurring ($this->_isInsideErrorHandlerLoop is a subtle clue too ;)
Why is it in a loop?
OK, #Bittarman gave me the answer in #ZFTalk on IRC. Here it is (and apologies that I will mark my own answer as correct..but I don't want to bug him even more to write it up here).
if( ($this->getRequest()->getActionName() == 'error') && ($this->getRequest()->getControllerName() == 'error')) {
return;
}
The reason for this is that the error handler has to disable itself
(by setting throw exceptions to true) when its in the error
handler loop. So you have
to make sure your exception condition does not occur in the error controller.
The ErrorHandler plugin is designed to catch exceptions thrown by the mvc-component, not by plugins. It hooks into the postDispatch and checks for exceptions of the dispatch - and nothing else.
It won't catch exceptions prior to this like in the preDispatch.
If you have a look at the source of the ErrorHandler Plugin you can see that it checks for Exceptions in the Request object. This only works if the frontController option 'throwExceptions' is set to false which makes him to catch exceptions and store them for later use (like the plugin handler).
In your case the exception isn't caught by the frontcontroller thus thrown to the very top of the application. You sure can edit the frontController to catch exceptions prior to the dispatch - but this isn't implemented intentional: everything prior to the dispatch can be seen as "booting" the application: any exception there is critical. Like in real booting, any exception there stops the application to run. So you really should avoid any exceptions there.
Update: Ok this was for the plugin part and forgot you wanted to know for the ActionHelper part. Those aren't executed by the FrontController but by the Zend_Controller_Action. As there they're part of the dispatching and caught by the FrontController and handled by the ErrorHandler plugin.
But what does the ErrorHandler do? It adds another request to the FrontController with your errorController. So another dispatching loop is done and again, your actionhelper does throws an exception. As the errorController request isn't different to any other request, the ErrorHandler plugin would catch it again and chain another request of the errorController. Which again.. i guess you can see where this would lead to - a loop. To prevent this there is a property to see if there was already an exception somewhere. This is to catch any exception thrown by the error handler. If the ErrorHandler plugin notices such an exception it overwrites the throwException property to true and throws the exception.
So the unhandled exception you can see is the exception which rises from the errorController request.
I can see the point that ActionHelpers can throw an exception - but you should be really careful with that for exactly this reason ;)
I am trying to use nunits new way of exception handling but I am finding it hard to find information on it and how to also use it with moq.
I have right now moq that throws a exception on a mocked method but I don't know how to use nunit to catch it and look at it.
There's a few different ways to do it; I use Assert.Throws.
var exception = Assert.Throws<YourTypeOfException>(()=> Action goes here);
e.g.
var exception = Assert
.Throws<ArgumentNullException>(()=> new ChimpPuncher(null));
You can then query the exception object further if you want, e.g.
Assert.That(exception.Message, Text.Contains("paramname");
Best way to mention is: [ExpectedException(typeof(ApplicationException))] above the test method.
Why can't you enclose the mocked method call in a try/catch block and catch the specific exception being thrown?