When I use the AddRange method from the Entity Framework and then call SaveChanges, if one of the Entities fails to be inserted into the DB, will everything be rollbacked?
I don't want to use explicit Transactions.
From msdn doc:
SaveChanges operates within a transaction. SaveChanges will roll back that transaction and throw an exception if any of the dirty ObjectStateEntry objects cannot be persisted.
https://msdn.microsoft.com/en-us/library/bb336792(v=vs.110).aspx
I hope it helps!
Related
I am trying to implement transaction management in EJB application with Openjpa as ORM tool.
I am trying to implement a scenario where if a db update operation fails for an entity, then db operations for all other entities in same transaction
also rollback. So I have an entity A and I explicitly set one of it's non-nullable field to null and call entitymanager.merge() method for this entity.I expect that due to non-nullable constraint db operation would fail and PersistenceException would be thrown. But nothing of that sort happens, though A's state is also not persisted.
But if I first call find() using A's id and then call merge(), I get exception.
I used to think that merge() alone is sufficient to take care of all. Why do I need to explicitly call find() before merge?
Changes are not required to be synchronized to the database until you call em.flush(), or commit the associated transaction.
I'm aware of two different scenarios in which exceptions can be produced when working with an Entity Framework DbContext:
Enumerating a query (could throw a EntityCommandExecutionException)
Calling SaveChanges (could throw a DbUpdateException)
Within a single instance of DbContext, I'm wanting to catch these exceptions, try to recover if applicable, and then repeat the operation.
Specifically, if a call to SaveChanges throws an exception because of a deadlock, I would like to retry the call to SaveChanges. I already know how to detect this situation and perform the retry.
I saw this answer here, which indicates that an SQL connection shouldn't be used after a deadlock. This indicates that I should restart the entire DbContext and higher-level operation to recover from such exceptions.
What I'm not sure about is whether it's safe to continue using the DbContext after it has thrown an exception such as this. Will it enter an unusable state? Will it still work but not function correctly? Will SaveChanges no longer occur transactionally?
If you don't supply the DbContext with an already opened SQL connection, the DbContext will open and close the connection for you when you call SaveChanges. In that case there is no danger in keeping the DbContext around, except of course that the entities the DbContext holds on to might be in an invalid state (because this could be the reason that the SQL exception was thrown).
Here's an example of a DbContext that is suppied by an opened SQL connection and transaction:
using (var connection = new SqlConnection("my connection"))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
using (var context = new DbContext(connection))
{
// Do useful stuff.
context.SaveChanges();
}
transaction.Commit();
}
}
If you supply the DbContext with a SqlConnection that runs in the context of a transaction, this answer holds.
Note that Entity Framework will not create a nested transaction. It simply checks whether the connection is "enlisted in user transaction". If SaveChanges already runs in a transaction, no transaction is started. Entity Framework however is unable to detect if the database has aborted the transaction because of a severe failure (such as a database deadlock). So if a first call to SaveChanges fails with something like a deadlock and you catch and recall SaveChanges, Entity Framework still thinks it is running inside a transaction.
This means that this second call is executed without a transaction and this means that when the operation fails halfway, the already executed statements will NOT be rolled back since there is no transaction to rollback.
The problem of the torn SaveChanges operation could have been prevented if Entity Framework used nested transactions, but it still wouldn't solve the general problem of consistency.
Entity Framework creates connections and transactions for us when we do not supply them explicitly. We only need/want to supply a connection and transaction explicitly when the call to SaveChanges is part of a bigger overall transaction. So even if EF created a nested transaction for us and committed this before returning from SaveChanges, we're in trouble if we call SaveChanges a second time, since this 'nested' transaction actually isn't nested at all. When EF commits this 'nested' transaction, it actually commits the only transaction there is, which means that the entire operation we needed to be atomic is torn; all changes done by SaveChanges are committed, while the operations that might came after this call didn't run. Obviously this is not a good place to be.
So moral of the story is that either you let Entity Framework handle connections and transactions for you and you can redo calls to SaveChanges without risk, or you handle transactions yourself and will have to fail fast when the database throws an exception; you shouldn't call SaveChanges again.
Is there a way to implement transactions in code first without having to write stored procedures?
I have some scenarios where multi-table entries need to be created with unique guids before a final table entry can be created. Is this something I can code using EF alone?
DbContext.SaveChanges() method uses a transaction . So it is Atomic and you don't want to use stored procedures. The unitOfWork patter is implemented in EF itself to accomplish this.
But let's say you are using two DbContext instances to d your job , then you need to wrap your work with a transaction scope like this,
using (var scpe=new TransactionScope()){
...
context1.SaveChanges();
....
context.SaveChanges();
scope.Complete();
}
SaveChanges operates within a transaction. SaveChanges will roll back
that transaction and throw an exception if any of the dirty
ObjectStateEntry objects cannot be persisted.
See the documentation
I am developing an application in C# by using the ADO.NET Entity Framework.
In many examples on the web I see that in order to add an element, newProduct, to an entity, let's assume Product, it is used the following code:
context.Products.Add(newProduct);
The method Add, however, it is not a member of Products so I cannot use it. Maybe the EF used in the examples is LinqToSQL.
However in ADO.NET there is a method AddObject:
context.AddObject("Products", newProduct)
and it works but I don't like it for two reasons:
1) I try to avoid as much as possible magic strings unless they are really the only resort to implement a functionality
2) It gives void as a return type, how can I check whether the insert was good or not?
I believe there is another way to insert my entities. Anybody might help?
1) I try to avoid as much as possible magic strings unless they are
really the only resort to implement a functionality
If context is an ObjectContext (EF <= 4.0), you should normally have a member in your derived context which represents the ObjectSet<Product> with the name Products or similar. You can use then:
context.Products.AddObject(newProduct);
Even if you don't have such a set in your context there is another strongly-typed option:
context.CreateObjectSet<Product>().AddObject(newProduct);
2) It gives void as a return type, how can I check whether the insert
was good or not?
AddObject does not perfrom the INSERT into the database at all. It only puts the object into Added state in the objectContext. The real INSERT happens later in a single transaction when you call SaveChanges.
Nonetheless, AddObject can fail, maybe if you add two objects with the same key into the context (if your entity does not have autogenerated identities for the key), or for other reasons. If so, AddObject will throw an exception which you shouldn't catch because it usually indicates a serious problem or bug in your code.
SaveChanges returns an int. But this int does not indicate that SaveChanges and inserting your object was successful. It only counts the number objects which are in Added state (will cause INSERT statement), in Modified state (will cause UPDATE statement) and in Deleted state (will cause DELETE statement) in the object context before the SQL statements get exceuted.
Again, if any of the SQL statements (like your INSERT) was not successful, SaveChanges will throw an exception. The exception can indicate problems already on client side or it can tell you that a problem during a SQL operation occured - for example: For a failed INSERT the exception might give you a message that the INSERT failed because there was already a row with the key you want to insert in the database or that required non-nullable columns are not filled in the entity you want to insert, etc. Also exceptions due to concurrency issues are possible among a lot of other exception types.
You can check if SaveChanges succeeded by catching possible exceptions:
try
{
int numberOfObjects = context.SaveChanges();
}
catch (SomeExceptionType e)
{
// What now?
}
BTW: The context.Products.Add(...) you've seen was most likely an example where context is a DbContext (EF >= 4.1). DbContext is a simplified API to Entity Framework (which still uses the core ObjectContext under the covers). In this API the method to insert a new entity is indeed called Add (method of DbSet<T>) and not AddObject.
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.