I have a java EE project using JPA (transaction-type="JTA"), hibernate as provider. I write my beans to handle the CRUD things. The program running in JBOSS 7 AS.
I have an EntityManagerDAO :
#Stateful
public class EntityManagerDao implements Serializable {
#PersistenceContext(unitName = "dtdJpa")
private EntityManager entityManager;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public Object updateObject(Object object) {
object = entityManager.merge(object);
return object;
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void createObject(Object object) {
entityManager.persist(object);
}
public void refresh(Object object) {
entityManager.refresh(object);
}
public <T> T find(Class<T> clazz, Long id) {
return entityManager.find(clazz, id);
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteObject(Object object) {
entityManager.remove(object);
}
}
but when I invoke deleteObject, this exception comes out.
java.lang.IllegalArgumentException: Removing a detached instance com.test.User#5
How is this caused and how can I solve it?
EntityManager#remove() works only on entities which are managed in the current transaction/context. In your case, you're retrieving the entity in an earlier transaction, storing it in the HTTP session and then attempting to remove it in a different transaction/context. This just won't work.
You need to check if the entity is managed by EntityManager#contains() and if not, then make it managed it EntityManager#merge().
Basically, the delete() method of your business service class should look like this:
em.remove(em.contains(entity) ? entity : em.merge(entity));
In my case, I got the same error, when I tried to delete an object
using,
session.delete(obj)
without creating any transaction before that.
And the problem is solved by creating the transaction first(session.beginTransaction() and then deleting the object.
I hope my answer will help someone :)
Sometimes its simply because you are missing the #Transaction annotation for add, remove, update operations.
I faced the same problem. The detached entity should be re-attached. As #BalusC mentioned, using EntityManager.merge() should be used to attach the detached entity. EntityManager.merge() generates SQL Query which fetches the current state of the entity, on which EntityManager.remove() has to be performed. But in my case it didn't worked.
Try EntityManager.remove(EntityManager.find(Class<T>,arg)) instead. It worked for me.
In my experience, if I query an object from the DB then closed the entity manager then do a DB delete, the problem happens. Or if I copy that loaded object to another instance then do a delete, this problem also happens.
In my opinion there are 2 things to keep note:
The object must be in the same session that was created by the Entity Manager
And the object mustn't be transferred to another object while the Entity Manager's session is still opened.
Cheers
Related
When repository.save(t) is called from my service, which is in turn called from my controller, all works just fine, and the object is inserted into the database table; But, when the service is called from my test class, Hibernate returns the created object but does not really flush the transaction into the database. I have tried using #Transactinal and #Commit in my test class and also on my #Test methods, but no difference in the result. I have also tried other solutions which involve using org.springframework.test.context.transaction.TestTransaction class, but any method call on this class throws an exception.
this is my super class for test:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class QaApplicationTest {
protected abstract void initializeTest() throws Exception;
protected abstract void cleanupTestEffects() throws Exception;
}
And this is my concrete test class:
public class RequestControllerTest extends QaApplicationTest {
#Autowired
private SiteService siteService;
#Autowired
private RequestService requestService;
#Test
#Transactional
public void givenObject_whenInsertToDB_thenCreated() throws Exception{
Site siteObject = siteService.save(siteObject); //Here I need a commit.
Request request = new Request(site.getId());
Request savedRequest = requestService.save(request); //Here database returns "Parent Key Not Found" error.
Assertions.assertTrue(savedRequest.getId()>0);
}
}
I know the #Transactional on test methods are used to roll back all the changes made inside the method, however, In my case, the changes are not even committed in the first place. And I have used #org.springframework.transaction.annotation.Transactional which is the correct annotation. I don't know which part I am doing wrong! Any idea?
My colleague found the issue; we had used a third-party library (Camunda) that had enabled batch-insert on Hibernate. So by disabling the batch operation the issue was resolved and the insert is actually taking place now. Not sure, why we faced this only in Spring Test and not in the main application though. if anyone has a comment, we appreciate it.
It feels so simple:
I have a ViewScoped bean (JPA2 + EE6 + Seam3, if that matters) where the user of the web application can invoke a method like this:
public void save() {
doEntityManagerStuff(); // manipulates data in the database
callRemoteWebservice(); // which is to read said data and propagate it to other systems
}
Unfortunately, save() starts a transaction at the opening curly bracket and doesn't commit it before the closing bracket, meaning that the new data is not available to the remote web service to read.
I have tried to explicitly extract and annotate the database work:
#TransactionAttribute(REQUIRES_NEW)
private void doEntityManagerStuff() {
blabla(); // database stuff
}
But that didn't have any impact at all. (Maybe because that's EJB stuff and I'm running on seam...?)
The only thing that worked for me so far was to inject #UserTransaction and force commit the transaction at the end of either save() or doEntityManagerStuff() but that felt incredibly dirty and dangerous.
The other alternative would be to turn off container-managed transactions for the entire project, but that means I'd have to make all my beans manage their transactions manually, just so I can make this one case work.
Is there a better way?
To answer my own question:
I only went half-way, and that's why it didn't work. I didn't know enough about EJBs and their boudaries, and naively though just annotating the doEntityManagerStuff(...) method with a transaction attribute in my view-scoped CDI/Seam bean would be enough.
It isn't.
When I moved said method into a separate, stateless EJB, injected that into my CDI/Seam bean and called it from there, everything worked as expected.
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class MyPersister {
...
public void doEntityManagerStuff() {
blabla(); // database stuff
}
...
}
and
#ViewScoped
public class MyWebsiteBean {
...
#Inject MyPersister persister;
...
public void save() {
persister.doEntityManagerStuff(); //uses its own transaction
callRemoteWebService();
}
...
}
Using autofac as my IoC framework.
I'd like to be able to set up my DbContext instance in my application's startup.
In my ASP.NET MVC 3 project, I register DbContext instance in Global.asax (PerLifetimeScope). But when I fire up my site on multiple browsers (or multiple tabs) at once, sometimes I get Object reference not set to an instance of an object. or New transaction is not allowed because there are other threads running in the session when I try to save changes back to database. Also I get
ExecuteReader requires an open and available Connection. The connection's current state: Broken. sometimes when I want to read data from database.
the errors seem to pop up randomly and I suspect it has something to do with my context's lifetime scope. here's my DbContext's overriden SaveChange method.
public class MyContext : DbContext
{
public override int SaveChanges()
{
var result = base.SaveChanges(); // Exception here
}
}
Here's how I register my context:
builder.Register(c => new MyContext("SomeConnectionString"))
.InstancePerLifetimeScope();
If I just have one open tab of my site in the browser everything works ok.
Also, It's worth mentioning I have CRUD operations with db every 5-10 seconds in my website by calling a controller method using Ajax.
StackTrace for New transaction is not allowed because there are other threads running in the session:
at System.Data.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.EntityClient.EntityConnection.BeginTransaction()
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs
StackTrace for Object reference not set to an instance of an object.:
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
at System.Data.Objects.ObjectStateManager.DetectChanges()
at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)
at System.Data.Entity.Internal.InternalContext.GetStateEntries()
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
at System.Data.Entity.DbContext.GetValidationErrors()
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs at
Registration of MyContext looks ok. Is it possible that some other service that takes a MyContext is registered as a singleton and being shared across threads?
I had the same issue, sporadic errors related to the DbContext while using Autofac to resolve the DbContext.
{System.Data.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
etc.
{System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
etc.
I found a class resembling the following in my code. The dependency resolution was occurring within a static method inside of the singleton. The object being resolved had a dependency on the DbContext. I haven't had any additional issues after I found a way to restructure this class so that it was no longer a singleton.
Perhaps you have a similar situation? Another thing to try might be to make your DbContext InstancePerHttpRequest. That could help identify whether this is the issue.
public class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton()
{
}
public static void DoSomething<TSource>(TSource source) where TSource : ISource
{
var items = DependencyResolver.Current.Resolve<IEnumerable<IDbContextConsumer<TSource>>>();
foreach (var item in items)
{
item.Execute(source);
}
}
}
Albahari writes in "c# 4.0 in a nutshell":
>
Although DataContext/ObjectContext implement IDisposable, you can (in general)
get away without disposing instances. Disposing forces the context’s connection
to dispose—but this is usually unnecessary because L2S and EF close connections
automatically whenever you finish retrieving results from a query
<<
This feels wrong and FxCop also complains if you are not diposing something that is IDisposable.
I have the following repository code:
public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{ ...
public void Add(TEntity entity)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
dbContext.Set<TEntity>().Add(entity);
dbContext.SaveChanges();
}
}
...
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
return dbContext.Set<TEntity>().Where(expression).ToList().AsEnumerable();
}
}
...
Note: I do not return IQueryable - lazy loading should not play a role.
Resolve DbContext is configured as PerResolveLifetimeManager.
Is this approach OK or do I need to reconsider this based on Albaharis description?
You should always call dispose if class exposes it. The statement claims that EF and L2S close connection whenever they finish operation - as I know the statement is correct but in the same time ADO.NET team also closes connection in Dispose method so perhaps there are situations when connection is not closed.
I'm working on EF 4.0 ObjectContext (yeah, I know...). I ended up looking at the code in DotPeek, and the dispose just nulls the reference to the connection and a few other things in the ObjectContext class.
When a connection is created (also found through DotPeek) it returns the existing instance. If the connection string is changed, it'll update the connection string for all instances.
That was my take on it at least. Need to look deeper but at first glance, it seems that you can get away with it.
I am using asp.net mvc 3, entity framework with structure map for IoC.
I have my own custom membership provider.
I had the same kind of problem when I was injecting the dbcontext object and the membership instances using StructureMap so removed this for my UserRepository.
The UserRepository now has a DBContext property which is initialised in the constructor.
Everytime a new user is created/updated (the method doing this is wrapping the dbcontext object in using statement), the next time the dbcontext is referenced I get ObjectDisposedException thrown.
I don't understand what I am doing wrong. Obviously, the membership provider class isn't instantiating the userRepository object everytime it needs it and when a user is updated, the context is disposed because of the using statement. But I thought this was standard practice?
Any help is greatly appreciated.
EDITED:
There is no complex code really. The set up is:
CustomMembershipProvider overrides the standard Membership provider (config file has got the details).
CustomMembershipProvider uses IUserService object that uses IUserRepository which is implemented by UserRepository that has the DBContext private object at class level.
In the UserRepository, I've got:
public void UpdateUser(User user)
{
using(_db)
{
... code to indicate that the user state has changed
_db.SaveChanges();
}
}
Once this code is run, the request is complete. But when another request is made to retrive role information or read the user from the database (in the UserRepository class), I get the ObjectDisposedException thrown. At this point nothing related to User Or Role works because they use the same UserRepository class whose _db variable has been disposed by UpdateUser.
I initially had StructureMap resolve the DBContext object, the customMembership object etc but have had to since remove it from StructureMap's mapping.
Everytime a new user is
created/updated (the method doing this
is wrapping the dbcontext object in
using statement), the next time the
dbcontext is referenced I get
ObjectDisposedException thrown.
DbContext is a disposable resource(Which implements IDisposable). So when you wrap it in a using block the context is disposed when the control flow goes out of the using block.
using(myContext)
{
//do stuff
}
//try to access myContext after the using block throw ObjectDisposedException
You have to re-design how you use the DbContext and when you are going to dispose it.