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.
Related
I have two transactions.
In first I select an entity, do validations, upload provided by client file to S3 and then update this entity with info about S3 file.
Second transaction is simply deleting this entity.
Now, assume that someone called first transaction and immediately second. Second one will proceed faster and first one will throw DbUpdateConcurrencyException, as selected entity no longer exists on update query.
I get DbUpdateConcurrencyException, when my transaction has IsolationLevel.ReadCommited. But if I set IsolationLevel.Serializable it throws InvalidOperationException with 40001 postgres code. Could someone explain why do I get different errors, because it seems to me that outcome should be the same, as both errors invoked by updating non-existing entity?
The 40001 error corresponds to the SQLSTATE serialization_failure (see the table of error codes).
It's generated by the database engine in serializable isolation level when it detects that there are concurrent transactions and this transaction may have produced a result that could not have been obtained if the concurrent transactions had been run serially.
When using IsolationLevel.ReadCommited, it's impossible to obtain this error, because choosing this level of isolation precisely means that the client-side doesn't want to have these isolation checks being done by the database.
On the other hand, the DbUpdateConcurrencyException is probably not generated by the database engine. It's generated by the entity framework. The database itself is fine with an UPDATE updating zero row, it's not an error at the SQL level.
I think you get the serialization failure if the database errors out first, and the DbUpdateConcurrencyException error if the database doesn't error out, but the second layer in the order of layering (the EF) does.
The typical way to deal with serialization failures, at the serializable isolation level, is for the client-side to retry the transaction when it gets a 40001 error. The retried transaction will have a fresh view of the data and hopefully will pass (otherwise, loop on retrying).
The typical way to deal with concurrency at lesser isolation levels like Read Committed it to explicitly lock objets before accessing them to force the serialization of concurrent transactions.
My C# application uses EF and calls min() on an int column to get the 'next' number in a sequence of numbers from a database table. The database table already has the next X numbers ready to go and my EF code just needs to get the 'next' one and after getting this number, the code then deletes that entry so the next request gets the following one etc. With one instance of the application all is fine, but with multiple users this leads to concurrency issues. Is there a design pattern for getting this next min() value in a serial fashion for all users, without resorting to a stored procedure? I'm using a mix of EF4.5 and EF5.
Thanks, Pete
Firstly, you can add an timestamp type column into your table and on Entity Framework property window set the concurrency mode to Fixed.
Doing that you enable optimistic concurrency check on the table. If there is another data context tries to interrupt your update, it will generate an excepton.
Check this link: http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx?Redirected=true
Alternatively, you can use a TransactionScope object on your select/update logic. You can simply wrap around your code logic with a TransactionScope logic and everything within the scope will be enforced by the transaction.
Check this link for more information:
TransactionScope vs Transaction in LINQ to SQL
We are contemplating the use of Entity Framework for a bulk upload job. Because we are interested in tracking the individual results of each recorded, I am trying to find out whether all items inserted are done as part of a transaction and if a single failure would cause a rollback, or if there is a way to track the result of each individual result.
I was contemplating just looping through the items and calling Save() on each and wrapping that in a try/catch block, but just calling save() on the context seems more effective if I can tap into the individual results.
Thanks!
By default each time you call SaveChanges all records that are pending are saved at once. All operations within a SaveChanges call are within a transaction (source) and so if a particular SaveChanges call it fails it will rollback the queries in that particular call, but obviously not previously successful calls.
Ultimately it depends on where you call SaveChanges as to how much of a rollback you'd get. You can extend the length of a transaction with TransactionScope see this article for some examples on how to extend the scope.
My own experience is that calling SaveChanges too often can really decrease performance, and slow the entire process down a lot. But obviously waiting too long can mean a greater memory footprint. I found that EF can easily handle several thousand rows without much of a memory problem.
Placing the code in a try...catch will assist you, but you may want to look at entity validation as you can place restrictions on the objects and then validation will occur on the objects before any SQL is generated.
I'd like to know what is the best practice to track and/or persist changes over time if I use EF. I'd like to get started with EF for a new project. What I need is a kind of change history.
That's how I did it before: If a record was created it was saved with an ID and with the same ID as InvariantID. If the record was updated i marked it as deleted and created a new record with the new values and a new ID but the same InvariantID. Like this I always had my current record but a history of changes as well.
This works perfectly fine for my scenarios. The amount of historical records is not an issue because I use this usually only for data that's not changing very often.
Is this build in EF somehow or what's the best way to get this behavior for EF?
No it is not build into EF and it will not work this way. I even don't think that it is a good approach on the database level because it makes referential integrity very complex.
With EF this will work only if you use following approach:
You will use conditional mapping for your entity - condition will be IsDeleted = 0. It will ensure that only non deleted entities will be used in queries.
You will have mapped stored procedure for delete operation to correctly set IsDeleted = 1 instead of really deleting the record
You will have to manually call DeleteObject to delete your record and after that you will insert new record - the reason is that EF is not able to deal with scenario where entity change its PK value during update.
Your entities will not be able to participate in relations unless you manually rebuild referential integrity with some other stored procedure
You will need stored procedure to query historical (deleted) records
A have a JPA entity that has timestamp field and is distinguished by a complex identifier field. What I need is to update timestamp in an entity that has already been stored, otherwise create and store new entity with the current timestamp.
As it turns out the task is not as simple as it seems from the first sight. The problem is that in concurrent environment I get nasty "Unique index or primary key violation" exception. Here's my code:
// Load existing entity, if any.
Entity e = entityManager.find(Entity.class, id);
if (e == null) {
// Could not find entity with the specified id in the database, so create new one.
e = entityManager.merge(new Entity(id));
}
// Set current time...
e.setTimestamp(new Date());
// ...and finally save entity.
entityManager.flush();
Please note that in this example entity identifier is not generated on insert, it is known in advance.
When two or more of threads run this block of code in parallel, they may simultaneously get null from entityManager.find(Entity.class, id) method call, so they will attempt to save two or more entities at the same time, with the same identifier resulting in error.
I think that there are few solutions to the problem.
Sure I could synchronize this code block with a global lock to prevent concurrent access to the database, but would it be the most efficient way?
Some databases support very handy MERGE statement that updates existing or creates new row if none exists. But I doubt that OpenJPA (JPA implementation of my choice) supports it.
Event if JPA does not support SQL MERGE, I can always fall back to plain old JDBC and do whatever I want with the database. But I don't want to leave comfortable API and mess with hairy JDBC+SQL combination.
There is a magic trick to fix it using standard JPA API only, but I don't know it yet.
Please help.
You are referring to the transaction isolation of JPA transactions. I.e. what is the behaviour of transactions when they access other transactions' resources.
According to this article:
READ_COMMITTED is the expected default Transaction Isolation level for using [..] EJB3 JPA
This means that - yes, you will have problems with the above code.
But JPA doesn't support custom isolation levels.
This thread discusses the topic more extensively. Depending on whether you use Spring or EJB, I think you can make use of the proper transaction strategy.