I have a stateless bean resposible for persisting entities to a database. This stateless bean is called by a message bean's onMessage method. The wired thing is that on the first message everything works fine, but on the next message the method responsible for persisting is invoked outside a transaction, even though the method is annotated with REQUIRES_NEW.
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public StateChange persistChange(long deviceId, ...) {
...
StateChange change = new StateChange(...);
em.persist(change);
em.refresh(change); // To provoke the error
return change;
}
Calling refresh triggers the following exception:
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
Any ideas? I'm fairly new to JTA so I might have missed something important?
I tried a lot to solve it and after about 16 hours or so it seems to be working. I'm not sure exactly what did the trick, but it might be the upgrade to Glassfish 2.1.
Finally able to sleep at night again!
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.
This came up time and again for us. After reading such a message, there's nothing intuitive to do and debug.
What this poorly-documented error is trying to say is that you accidentally set up a system in which tracking changes causes more changes.
When Entity Framework changed a property on one of your entities, such as during SaveChanges with identity ID updates, you ran code that changed other tracked properties.
For example, the property that Entity Framework was setting triggered an event, perhaps INotifyPropertyChanged, which perhaps was subscribed to by a BindingSource or some binding list, whose ListChanged event handler was in the UI and triggered a calculation of some other property, and the change tracker detected the second property change.
The simple diagnosis is to place a breakpoint on the SaveChanges() call and immediately after the SaveChanges call(). When the first breakpoint is hit, place a breakpoint on each event handler that could possibly be triggered. (BindingSources are notorious for multiplying each other's events.) Continue debugging. If any breakpoint is hit other than the point immediately following SaveChanges, you know where the problem is.
The simple solution is to set a flag, such as IsSaving, on each side of the SaveChanges call. Then in each misbehaving event handler, do a simple check and do not modify any entities if the DbContext is in the process of saving. Make sure you use finally in case SaveChanges throws an exception that you catch at a higher level:
IsSaving = true;
try
{
await db.SaveChangesAsync()
}
finally
{
IsSaving = false;
}
(One other possibility is that you were changing the entity from multiple threads — never involve the change tracker in multiple threads!)
I had the exact same issue. I had wired to the INotifyPropertyChanged event that created the possibility for a property to change during the SaveChanges() call. I think it is a better practice to unwire the event handlers of you tracked entities when performing dbContext.SaveChanges(), Remove().
I'll explain my experience with this error, hoping it might help someone. And thanks to jnm2 for beautiful explanation.
I had Invoice and Receipt entities, and InvoiceViewModel.
Thie ViewModel was subscribed to Invoice property changed, inside which it was raising CanExecuteChanged events.
I added Receipt to Invoice navigation property and called SaveChanges(), which raised Invoice.ReceiptID property changed and triggered OnPropertyChanged event handler on the ViewModel, which in turn raised all kinds of CanExecuteChanged events.
The problem was that one of the CanCommandNameExecute methods was calling Context.ChangeTracker.HasChanges() which ultimately threw an exception.
How I fixed it?
I followed jnm2, I flagged VM with IsSaving and checked for the flag inside OnPropertyChanged event handler.
Once again, thanks jnm2, and hope someone finds this helpful as well.
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.
I am having a tough time to understand why this code is failing
I have a test method
IUnitOfWork unitofwork = EFUnitOfWork.CreateInstance();
IRepository<InformationRequest> informationRequestRepository = unitofwork.CreateRepository<InformationRequest>();
IEnumerable<InformationRequest> requests = informationRequestRepository.ToList();
unitofwork.Dispose();
EFUnityOfWork.CreateInstance calls the EFUnitOfwork Constructor
public EFUnitOfWork()
{
_currentContext = new MyDataContext();
}
Here is the code for CreateRepository
public IRepository<T> CreateRepository<T>()
{
return new Repository<T>(_currentContext);
}
The test above doesnt work on a load test. When i try to run it it says
System.Data.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
I am disposing the context and creating a new one everytime. I dont understand where i am going wrong
Your code EFUnitOfWork.CreateInstance() is a static method.
When 2 threads call this at the same time they could get back the same context. Then you could get the error that you see.
You could fix it by locking such that it is only called by one thread at a time. But time would introduce a performance bottleneck.