Entity Framework Transaction across multiple SaveChanges - entity-framework

I am creating an application which uses WCF (4.5), EF (6.1), Unity (3.5) and Unity3.Wcf (3.5)
The application needs to run a monthly process which checks for changes that have happened in last month and create a record for an approval process.
This process will be triggered by a call to a WCF service method.
This is the basic logic:
Get collection of Things
For each Thing:
Get collection of ThingChanges
Calculate changed Amount
Create New ThingApproval
Update each ThingChange in ThingChanges with ThingApproval.ID
Now, as far as I am aware, in order to get ThingApproval.ID, I need to do SaveChanges after Create New ThingApproval which will populate with the ID from the DB. I then need to do a further SaveChanges either after each Update or once after the for each completes to commit all the updates.
If any part of this process fails, it needs to rollback ALL changes, back to before the first SaveChanges
How can I implement this?

I ended up implementing the GNaP.Data.Scope.EntityFramework package which gives full control of the DB Context, including transactional.

Related

EF Core Create database row if not exists

So I'm hitting my webservice to save a row in the database if the id doesn't already exist. So I do this in two steps. First I run a select on the context to bring back the entity with the given id. If that returns null, I create a new entity and call saveChanges. This works perfectly almost always. However, when there are multiple requests hitting the webserver at the same time, there is a chance that 2 requests could run at pretty much the same time. When this happens, there is the chance that they both create a row. This is actually happening.
How would you handle this situation?
p.s. I'm using EntityFramework Core.

Is #PostRemove out of transaction?

I found following information from the spec. But it's not clear enough for me who is not an english native.
The PostPersist and PostRemove callback methods are invoked for an entity after the entity has been made persistent or removed. These callbacks will also be invoked on all entities to which these operations are cascaded. The PostPersist and PostRemove methods will be invoked after the database insert and delete operations respectively. These database operations may occur directly after the persist, merge, or remove operations have been invoked or they may occur directly after a flush operation has occurred (which may be at the end of the transaction). Generated primary key values are available in the PostPersist method.
My question is any transaction related jobs can be rolled back after #PostRemove?
Let's say my entity deletes some offline files on #PostRemove
class MyEntity {
#PostRemove
private void onPostRemove() {
// delete offline files related to this entity
// not restorable!
}
}
Is it possible that those offline files deleted from the storage and the entity still left in the database? (by rollback?)
Yes, it is possible that your files are deleted and your entites are still left in db after a rollback. #PostRemove is in transaction.
If you want to be absolutely sure that your files are deleted if and only if the transaction is successfully completed then you should delete the files after the commit() succeeds not using the callback methods. But if you also need to be sure that the entity is removed if and only if the file is deleted, then you have a problem. You need a transactional way of accessing the file system.
For a simple solution move your files into a to_be_deleted-folder during the db-transaction. Therefore you can use the callback methods. The files are finally deleted when commit() succeeds and restored on failure.
If you want to elaborate it a bit more and your application is running in a java EE container, then you might want to look at CDI events or even at a jca adapter. If you are using Spring you can register a TransactionSynchronizationAdapter see this answer.
It depends.
If you're using multiple flushes (EntityManager#flush()), the transaction could still be rolled back. Otherwise, any callbacks prefixed with Post are executed after the database transaction is complete.

Entity Framework Order of Operations

I have a transaction type system where an object is created and stored and then sent off to another service for further processing and then the object is updated upon return. I have been doing some quality checks in my system and I noticed that a handful of records are logged in the secondary system but not in my main application. Is this possible? Does context.savechanges() move on before returning a result?

entity framework concurrency: transactions or concurrency fixed?

I need to make stock control, so I need to ensure that when I modified the amount of product, is doing in the right way. I am using Entity framework 4.0
For example, if I use a transaction, when I load the record from the database, the recored is blocked, so I can substract or add to the loaded amount, the number of items that I need. However, this block the record in the database and perhaps for performance reasons is not the best way. This makes me ask when to use transactions with EF.
The other option is to use the concurrency fixed of entity framework, using a timespan column to detect if the record has been changed. In this case, if the record has been modified between my load and my update, I get the exception of concurrency. But it could occur that in my exception handler, if I update my context with the database data, between my refresh and the savechanges could be changed again.
Other problem is I finally can save the changes. For example, I have 10 units, I need to substract 8 but between my load and my update, other person substract 5 units. If I subtract 8, then in stock I have -3 units. This is not possible. If I have a transaction, I load the record, is blocked, so I can check if I have enough units, if yes, I can subtrack, if not, I send an exception.
So my question is, I know that EF is a transaction by itself, but it exists also transactions in EF, so it would be useful in some cases. When to use EF and cocurrency fixed and when to use transactions?
Thanks.
Daimroc.
Transactions should not be used to solve concurrency. You should make transactions as short as possible to not block your databases. The way to go here is optimistic concurrency - in the database (SqlServer) you create a rowversion column that changes automatically each time a row is modified. You use it as concurrency token. When saving changes EF checks this against the value on the entity and if they don't match it throws an exception.
Note that for SaveChanges EF always creates a transaction since typically you save more than one entity and if something goes wrong the database needs to be reverted to the original state - otherwise it would be in a corrupt state.
To prevent from going below zero - if you use the optimistic concurrency - you won't be able to save if the value in the database changed since the concurrency token will be different because row was modified and therefore the check on the client should be sufficient. Alternatively you could map saving an entity to a stored procedure that will check the value before saving and would return an error if the value after saving would be incorrect.

WF4 TransactionScope containing several custom activities with EF4 database updates

I have created several custom activities that update tables in my DB (in this case SQL Server Compact), using Entity Framework 4 with POCOs.
If I put more than one of these inside a WF4 TransactionScope activity, I'm running into problems: EF disposes the DB connection after the first activity has finished, and when the next DB activity tries to do a DB update a new connection is built up. At this moment an exception is thrown.
System.Activities.WorkflowApplicationAbortedException : The workflow has been aborted.
----> System.Data.EntityException : The underlying provider failed on Open.
----> System.InvalidOperationException : The connection object can not be enlisted in transaction scope.
Do I have to keep the EF connection open during the whole transaction scope? How can I do that? Create an explicit custom activity for that, or is there a standard way?
My current workaround goes like this: I created a new code activity that creates our ObjectContext and explicitely calls dbContext.Connection.Open(). It returns the ObjectContext, which is then saved in a workflow variable. That one is passed to all the DB related activities as an InArgument<>. Inside my DB activities, I use this ObjectContext if it is passed in, otherwise I create a new one.
This does work, but I'm not satisfied with this solution: It needs the new InArgument for every DB related activity. In the workflow designer, I have to insert that special OpenDatabaseConnection activity inside the transaction scope, and then make sure that the correct variable is passed into all DB activities. This seems to be very inelegant and error prone, especially if other team members have to use these DB activities.
What would be a better way to handle this?
The problem is that when you open a second connection in the same transaction scope, an attempt is made to promote the transaction to a distributed transaction (even though there's nothing distributed about it since you connect to the same database). SQL Server CE doesn't support this scenario.
What I would do is create a custom 'container' activity that opens (and closes) the connection and makes it available to child activities. This is still not optimal but at least you no longer need to pass InArgument's around. You get the following activity tree:
TransactionScope
InitializeConnection
Sequence
CustomDataActivity1
CustomDataActivity2
CustomDataActivity3
InitializeConnection is a NativeActivity that uses NativeActivityContext.Properties to expose the connection (or the ObjectContext) to child activities.
Make sure you implement proper error handling to ensure you close the connection at all times.
NOTE: Distributed transactions are supported by the full SQL Server only through a Windows service called MSDTC (Microsoft Distributed Transaction Coordinator). You can find this one in your 'Local Services'. Since SQL Server CE is a database that should be able to operate completely standalone, it makes sense that it has no dependency on MSDTC. Therefore it has no support for distributed transactions.