EntityFramework Insert fails due to Trigger and OptimisticConcurrencyException is thrown, how to handle it? - entity-framework

I have a trigger in DB that forbids inserting duplicated data. When I enter duplicated data, it adds nothing to the table, OptimisticConcurrencyException is thrown and I am swallowing (ignoring) this exception. When I try to enter new correct object, EF tries to run both INSERTs and it fails again on the first one.
How can I recover from this, all examples are discussing failed UPDATES, is there anything about INSERT? As I have read creating new DatabaseContext will solve the problem, but I cannot do it that way.

Creating a new DatabaseContext is always the best choice (since Hibernate).
In your case you need to remove the entity that caused the error from the context.
((IObjectContextAdapter)context).ObjectContext.Detach(entity);

You can ask ObjectContext to ignore all the changes after the ignorable exception is thrown. This way the added entity is marked Unchanged; hence in the next SaveChanges call, context won't consider it to manipulate DB:
(yourContextObject as IObjectContextAdapter).AcceptAllChanges();

Related

Entity Framework 5 - "Conflicting Changes Detected"

In our EF 5 application, when we get a SQL Server deadlock error on an insert or update, we immediately try the operation again. However, when we attempt to do so, we're getting the following error:
"Conflicting changes detected. This may happen when trying to insert multiple entities with the same key."
This error is not coming from SQL Server. This is an EF 5 error. And we are not attempting to insert multiple entities with the same key. IOW, we're not attempting to insert a duplicate row. However, I suspect this error means something else. But I'm not entirely certain I know what the issue is. If I had to guess, I would say that on the first attempt, EF sees where trying to insert an entity. It fails because of a deadlock. When we immediately try again, EF thinks we're trying to do the very same operation again, with the same key, and doesn't like it. Not sure how to get around this.
It sounds like you might be trying to execute your queries against the same instance of the DbContext. In which case, your changes are already pending from the last try.
Since there is no “undo pending changes” on the context, you must dispose and recreate the context in between “retries”.

The specified table does not exist. [ __MigrationHistory ]

I've been using the following method since Entity Framework Code First became available:
public virtual void CreateDatabase()
{
var dbContext = _dbContextLocator.Current;
dbContext.Database.Delete();
dbContext.Database.Create();
dbContext.Database.Initialize(true);
}
Recently, I noticed that when dbContext.Database.Create() is hit, I get the following exception:
System.Data.SqlServerCe.SqlCeException occurred
Message=The specified table does not exist. [ __MigrationHistory ]
Source=SQL Server Compact ADO.NET Data Provider
ErrorCode=-2147467259
HResult=-2147217865
NativeError=0
StackTrace: at System.Data.SqlServerCe.SqlCeCommand.ProcessResults(Int32 hr)
InnerException:
If I go to Debug - Exceptions and check Thrown for "Common Language Runtime Exceptions", this causes execution to stop, and I get the above exception. If I uncheck it, the database seems to get created properly, but I get four repeats of the following error statements in my Output window:
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in System.Data.SqlServerCe.dll
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in System.Data.SqlServerCe.dll
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in System.Data.SqlServerCe.Entity.dll
A first chance exception of type 'System.Data.EntityCommandExecutionException' occurred in System.Data.Entity.dll
A first chance exception of type 'System.Data.EntityCommandExecutionException' occurred in System.Data.Entity.dll
A first chance exception of type 'System.Data.EntityCommandExecutionException' occurred in System.Data.Entity.dll
Placing a try/catch block around dbContext.Database.Create() has no effect.
My goal is to create a completely blank database, then fill it with data manually. I do not wish to use the new Migrations feature of Entity Framework.
What can I do to eliminate the first chance exceptions?
My goal is to create a completely blank database
Assume you mean a database with the actual schema objects required by your model?
If so, you have two options:
1) Ignore the exceptions - With SqlCE, EF uses the Migrations pipeline internally when creating databases. The exceptions are an implementation detail of how Migrations determines existence of the __MigrationHistory table.
2) Use the legacy APIs - The database creation APIs on ObjectContext use the legacy, non-migrations code path. Cast your DbContext to IObjectContextAdapter to obtain an ObjectContext reference.

EntityManager merge throwing EntityExists exception

In my EJB project deployed on WAS 6.1, when I try to call EntityManamger.merge(obj), I get this exception:
Exception data: <openjpa-1.0.4-SNAPSHOT-r420667:955062 nonfatal store error> org.apache.openjpa.persistence.EntityExistsException: Attempt to persist detached object "com.data.entity.SomeEntity#23aa23aa". If this is a new instance, make sure any versino and/or auto-generated primary key fields are null/default when persisting.
FailedObject: com.bmo.ctp.data.entity.attribute.RoleResServiceAttribute#23aa23aa
at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2368)
at org.apache.openjpa.kernel.AttachStrategy.persist(AttachStrategy.java:94)
at org.apache.openjpa.kernel.VersionAttachStrategy.attach(VersionAttachStrategy.java:95)
at org.apache.openjpa.kernel.AttachManager.attach(AttachManager.java:241)
at org.apache.openjpa.kernel.AttachStrategy.attachCollection(AttachStrategy.java:333)
at org.apache.openjpa.kernel.AttachStrategy.replaceCollection(AttachStrategy.java:301)
at org.apache.openjpa.kernel.AttachStrategy.attachField(AttachStrategy.java:220)
at org.apache.openjpa.kernel.VersionAttachStrategy.attach(VersionAttachStrategy.java:157)
at org.apache.openjpa.kernel.AttachManager.attach(AttachManager.java:241)
at org.apache.openjpa.kernel.AttachManager.attach(AttachManager.java:101)
at org.apache.openjpa.kernel.BrokerImpl.attach(BrokerImpl.java:3161)
at org.apache.openjpa.kernel.DelegatingBroker.attach(DelegatingBroker.java:1142)
at org.apache.openjpa.persistence.EntityManagerImpl.merge(EntityManagerImpl.java:665)
at com.ibm.ws.jpa.management.JPAExEmInvocation.merge(JPAExEmInvocation.java:335)
at com.ibm.ws.jpa.management.JPAEntityManager.merge(JPAEntityManager.java:123)
I do not have the source for JPAEntityManager.java; but I thought the EntityExistsException cannot be thrown by the merge() operation since merge will first do a check to see if entity exists. If not, insert it. If yes, update it.
What is going wrong here?
Please check how your entitymanager checks the existence of an entity. Is it using Cache? or is it using a DB Query. This issue generally occurs, if the existence check is done through cache.
if you are using eclipselink JPA, this configuration is maintained in orm.xml
Thanks,
Anand

jpa concurrency CMT exception handling

I use EntityManager to save/update my entities in database and Hibernate as jpa provider. My transactions are handled by container.
The problem: I need to add an entity that might have been already stored in database, so an exception will be thrown. In this case I need to repeat insertion but with another value. But as long as an exception is thrown the session has gone bad and I need to create a new session and rollback the transaction. How can I do this when I'm using CMT? Or if there is another way to do this?
Thank you.
You could use the TransactionAttribute(REQUIRES_NEW) for your persistence method. If the bean invoking your method will catch an exception, it might do some changes and invoke the method once again.
This will rollback just the persistence-method transaction - not the invoking bean one.
However, remember that if your Use Case doesn't require you to do EntityManager#persistence(-), you might be interested in EntityManager#merge(-) operation. It will persist the entity if it doesn't already exist or update it if it already exists (the existence is checked based on the PK).
HTH.
You might want to use EntityManager#find(Class, PK) to check for an already persisted entity. A null result means there's no such entity ( ----> persist(.) ), otherwise you update with the merge(.) method.

Removing an entity, but using the same primary key to add a similar entity after the removal

Im trying to remove an entity which has a unique PK like : 80253
I remove this entity by doing the follow lines of code:
myEntityType1 = getEntityManager().find(MyEntityType1.class, 80253);
getEntityManager().remove(myEntityType1);
getEntityManager().flush();
These bits of code actually deletes the rows from my database and all its cascading objects properly, and Im very happy about this. Now the problem occurs when I now need to create a similar entity that uses the same primary key (which should now be gone right?).
MyEntityType2 myEntityType2 = new MyEntityType2 ();
myEntityType2.copyData(myEntityType1); //access the data from the other object
//and retrieves the id 80253. myEntityType2 now has 80253 as ID.
getEntitymanager().persist(myEntityType2);
Now this is where I get a unique constraint SQL error. Im trying to insert a ID which already exists and the changes are automatically rolled back (the old entity is no longer deleted). This happens after I see in my logger that toplink has deleted the records of the old entity.
Does anyone know how this happens, and why its not working? For the record Ive tried merging, closing, clearing of the entityManager, but nothing seems to work.
It seems to me that JPA might do some bad caching or something. I hope someone has a good answer for me! =)
Update: Theres no longer an issue with unique ID constraints, but I create a new subclass with the same primary key which has been deleted I get the following exception:
Exception Description: Trying to invoke [setApprovedWhen] on the object [null]. The
number of actual and formal parameters differs, or an unwrapping conversion has failed.
Internal Exception: java.lang.IllegalArgumentException: object is not an instance of
declaring class
It seems to me that it wont let me change the object into a different subclass?
EDIT:
Try with explicitly start and commit transaction.
Deleting an entity is as simple as
calling EntityManager method
remove(Object entity) as the following
example shows. The entity you delete
must be managed: that is, it must have
been previously read in the current
persistence context.
entityManager.getTransaction().begin();
myEntityType1 = getEntityManager().find(MyEntityType1.class, 80253);
getEntityManager().remove(myEntityType1);
entityManager.getTransaction().commit();
When the transaction is completed, or
you call EntityManager method flush(),
the entity will be deleted.
In a container managed persistence
context the transaction boundaries
will be controlled by the container.