Answered by:
I have a repository that looks like this

Question
-
User1034446946 posted
public void Update(List<T> entity) { if (entity == null) throw new ArgumentNullException("entity"); this._context.SaveChanges(); }
now i want to add a concurrency check, and if a record fails the check it doesn't get update but doesn't stop the others being updated, everything I have seen uses try catch but i am not sure how i get arround it.
Any thoughts would be appriciated.
Monday, March 19, 2018 12:46 AM
Answers
-
User1034446946 posted
After looking into Transaction further i think Transaction would will do what I want, as it offers pessimistic concurrency.
Thanks for the help
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, March 22, 2018 1:48 AM
All replies
-
User1120430333 posted
now i want to add a concurrency check, and if a record fails the check it doesn't get update but doesn't stop the others being updated, everything I have seen uses try catch but i am not sure how i get arround it.
I guess this is one of the drawbacks about using a generic repository. It's too generic.
And about letting the other updates complete and stopping one with a concurrency issue in a series of related updates doesn't make a lot of sense. It should be treated as a single transaction of they all are updated successfully or non are updated and rollback, IMHO. That's if this is what you are talking about stopping an update on concurrency on a series of related updates.
However, I don't see why you just can't have logic to check concurrency on a timestamp basis. Maybe user-id and timestamp can be used and not just a timestamp solely. If they don't match, the ones held and checked against the ones on current record read from database, then you stop the update.
Myself, I learned not to use a generic repository, because one may need to take more control than what a generic repository can provide. There is nothing wrong what the repository pattern, and the pattern can be used in a non-generic manner as well.
The is nothing wrong in having more than one repository object being used in the repository pattern.
Sometimes, it's viable to not even use the Repository pattern and go with a Data Access Object pattern or a combination of the two. Lately, I have just ignored the Repository pattern and just went with a DAL using the DAO pattern that gives me more control of CRUD at the low-level database activities.
It's the DAO that gives one the control.
http://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx
Monday, March 19, 2018 8:57 AM -
User1034446946 posted
now i want to add a concurrency check, and if a record fails the check it doesn't get update but doesn't stop the others being updated, everything I have seen uses try catch but i am not sure how i get arround it.
I guess this is one of the drawbacks about using a generic repository. It's too generic.
And about letting the other updates complete and stopping one with a concurrency issue in a series of related updates doesn't make a lot of sense. It should be treated as a single transaction of they all are updated successfully or non are updated and rollback, IMHO. That's if this is what you are talking about stopping an update on concurrency on a series of related updates.
However, I don't see why you just can't have logic to check concurrency on a timestamp basis. Maybe user-id and timestamp can be used and not just a timestamp solely. If they don't match, the ones held and checked against the ones on current record read from database, then you stop the update.
Myself, I learned not to use a generic repository, because one may need to take more control than what a generic repository can provide. There is nothing wrong what the repository pattern, and the pattern can be used in a non-generic manner as well.
The is nothing wrong in having more than one repository object being used in the repository pattern.
Sometimes, it's viable to not even use the Repository pattern and go with a Data Access Object pattern or a combination of the two. Lately, I have just ignored the Repository pattern and just went with a DAL using the DAO pattern that gives me more control of CRUD at the low-level database activities.
It's the DAO that gives one the control.
http://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx
So is it just a case of looping through the single entities and checking for concurrency and running the update if everything is fine, or am i missing something?
I was thinking about using transation to ensure these records aren't updated at the same time, but I don't want to lock the records to other processes.
I have one process thats really important its only done once, and although I could put it in its own method, that would require its own call to action, and I don't want that either i want it to be automated but that means putting it in a method which uses the records specifically after this method has been called, hence the concurrency issue.
Monday, March 19, 2018 2:15 PM -
User1120430333 posted
So is it just a case of looping through the single entities and checking for concurrency and running the update if everything is fine, or am i missing something?
When I am looking to do a concurrency check, it involves the user looking at a single main record that has been presented to the user on an update screen (there could be data from other records that makeup the screen), the user tries to save the main record for update and it has been updated by another user first before the current user can save the update.
It could be nothing else but the current user-id and a timestamp is being saved on the main record, because the user did nothing to change data on the main record. But other data on the screen has changed belonging to other tables.
Now, other records may be updated during the save when the user pushed the 'Save' button. But there should only be one record that triggers the other records in tables to be updated or inserted in the code execution. If the main record being updated by a user on a screen based on a concurrency check can't be passed, then none of the other records in tables for update or insert are done, and the save process is stopped due to the concurrency check couldn't be passed on the main record for update. A user friendly message is displayed to the user as to why the Save cannot be done.
I was thinking about using transation to ensure these records aren't updated at the same time, but I don't want to lock the records to other processes.
The transaction should be that all the records in all tables are successfully saved during a transaction, or all records a rolled back if one record is not successfully saved during the save transaction.
Monday, March 19, 2018 9:35 PM -
User-832373396 posted
Hi EnenDaveyBoy,
oncurrency check, and if a record fails the check it doesn't get update but doesn't stop the others being updated, everything I have seen uses try catch but i am not sure how i get arround it.Sir, I recommend this Unit of Work pattern to you :), Unit of Work pattern could to make sure the all commands all are success or failure because we will add Transaction function, commonly; after writing all commands, we put all the commands together with Unit of Work pattern, then call the saving command;
Here is the partial code about unitofwork, it is a design pattern and recommended by Microsoft
var courses = unitOfWork.CourseRepository.Get(includeProperties: "Department"); // ... Course course = unitOfWork.CourseRepository.GetByID(id); // ... unitOfWork.CourseRepository.Insert(course); unitOfWork.Save(); // ... Course course = unitOfWork.CourseRepository.GetByID(id); // ... unitOfWork.CourseRepository.Update(course); unitOfWork.Save(); // ... var departmentsQuery = unitOfWork.DepartmentRepository.Get( orderBy: q => q.OrderBy(d => d.Name)); // ... Course course = unitOfWork.CourseRepository.GetByID(id); // ... unitOfWork.CourseRepository.Delete(id); unitOfWork.Save(); // ... unitOfWork.Dispose();
Official article Guide
- https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application#implement-a-generic-repository-and-a-unit-of-work-class
- The unit of work class serves one purpose: to make sure that when you use multiple repositories, they share a single database context. That way, when a unit of work is complete you can call <g class="gr_ gr_606 gr-alert gr_gramm gr_inline_cards gr_run_anim
Style multiReplace" id="606" data-gr-id="606">the </g>
SaveChanges
<g class="gr_ gr_606 gr-alert gr_gramm gr_inline_cards gr_disable_anim_appear Style multiReplace" id="606" data-gr-id="606"> method</g> on that instance of the context and be assured that all related changes will be coordinated. All that the class needs <g class="gr_ gr_608 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar multiReplace" id="608" data-gr-id="608">is</g> aSave
method and a property for each repository. Each repository property returns a repository instance that has been instantiated using the same database context instance as the other repository instances.
With regards, Angelina Jolie
Tuesday, March 20, 2018 10:06 AM -
User1034446946 posted
Hi EnenDaveyBoy,
EnenDaveyBoy
oncurrency check, and if a record fails the check it doesn't get update but doesn't stop the others being updated, everything I have seen uses try catch but i am not sure how i get arround it.Sir, I recommend this Unit of Work pattern to you :), Unit of Work pattern could to make sure the all commands all are success or failure because we will add Transaction function, commonly; after writing all commands, we put all the commands together with Unit of Work pattern, then call the saving command;
Here is the partial code about unitofwork, it is a design pattern and recommended by Microsoft
var courses = unitOfWork.CourseRepository.Get(includeProperties: "Department"); // ... Course course = unitOfWork.CourseRepository.GetByID(id); // ... unitOfWork.CourseRepository.Insert(course); unitOfWork.Save(); // ... Course course = unitOfWork.CourseRepository.GetByID(id); // ... unitOfWork.CourseRepository.Update(course); unitOfWork.Save(); // ... var departmentsQuery = unitOfWork.DepartmentRepository.Get( orderBy: q => q.OrderBy(d => d.Name)); // ... Course course = unitOfWork.CourseRepository.GetByID(id); // ... unitOfWork.CourseRepository.Delete(id); unitOfWork.Save(); // ... unitOfWork.Dispose();
Official article Guide
- https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application#implement-a-generic-repository-and-a-unit-of-work-class
- The unit of work class serves one purpose: to make sure that when you use multiple repositories, they share a single database context. That way, when a unit of work is complete you can call the
SaveChanges
method on that instance of the context and be assured that all related changes will be coordinated. All that the class needs is aSave
method and a property for each repository. Each repository property returns a repository instance that has been instantiated using the same database context instance as the other repository instances.
With regards, Angelina Jolie
From my under standing a unit of work with save all the records at the same time for that users request, but it won't stop two people accessing the same record at the same time.
All concurrenct examples I have seen work off a single record in a CRUD operation.
Tuesday, March 20, 2018 3:29 PM -
User475983607 posted
The MS docs explain how to handle concurrency.
Most likely your design will need a little refactoring to add this feature.
Tuesday, March 20, 2018 3:45 PM -
User1120430333 posted
From my under standing a unit of work with save all the records at the same time for that users request, but it won't stop two people accessing the same record at the same time.
All concurrenct examples I have seen work off a single record in a CRUD operation.That's all I have ever seen or done that started for me back in the 1980(s) with CICS and VSAM on the IBM Mainframes using COBOL. And I have carried that concept ito the MS platform in the 1990(s) with COM , to present .NET technology.
It is simple and effective. And if it's not broke why fix it? :)
Tuesday, March 20, 2018 9:08 PM -
User1034446946 posted
From my under standing a unit of work with save all the records at the same time for that users request, but it won't stop two people accessing the same record at the same time.
All concurrenct examples I have seen work off a single record in a CRUD operation.That's all I have ever seen or done that started for me back in the 1980(s) with CICS and VSAM on the IBM Mainframes using COBOL. And I have carried that concept ito the MS platform in the 1990(s) with COM , to present .NET technology.
It is simple and effective. And if it's not broke why fix it? :)
Wednesday, March 21, 2018 12:31 AM -
User1034446946 posted
The MS docs explain how to handle concurrency.
Most likely your design will need a little refactoring to add this feature.
I might just have to try some stuff and see what happens although im not sure how to test it when i get something working
Wednesday, March 21, 2018 12:45 AM -
User1120430333 posted
DA924
From my under standing a unit of work with save all the records at the same time for that users request, but it won't stop two people accessing the same record at the same time.
All concurrenct examples I have seen work off a single record in a CRUD operation.That's all I have ever seen or done that started for me back in the 1980(s) with CICS and VSAM on the IBM Mainframes using COBOL. And I have carried that concept ito the MS platform in the 1990(s) with COM , to present .NET technology.
It is simple and effective. And if it's not broke why fix it? :)
Sorry i just don't understand how the Unit of Work fixes a concurrency issue, where the same record can't be updated by two people at the same time.
I am not talking about the UoW pattern. I am talking about the concurrency concept of the main record checked in the main table for concurrency before persisting the other records in other tables. There was no UoW pattern in the 1980(s). I don't think the UoW pattern was even known on the .NET platform until EF was introduced, like in year 2008.
Wednesday, March 21, 2018 2:00 AM -
User1034446946 posted
So is it just a case of looping through the single entities and checking for concurrency and running the update if everything is fine, or am i missing something?
When I am looking to do a concurrency check, it involves the user looking at a single main record that has been presented to the user on an update screen (there could be data from other records that makeup the screen), the user tries to save the main record for update and it has been updated by another user first before the current user can save the update.
It could be nothing else but the current user-id and a timestamp is being saved on the main record, because the user did nothing to change data on the main record. But other data on the screen has changed belonging to other tables.
Now, other records may be updated during the save when the user pushed the 'Save' button. But there should only be one record that triggers the other records in tables to be updated or inserted in the code execution. If the main record being updated by a user on a screen based on a concurrency check can't be passed, then none of the other records in tables for update or insert are done, and the save process is stopped due to the concurrency check couldn't be passed on the main record for update. A user friendly message is displayed to the user as to why the Save cannot be done.
What you have described is what i want to do, however there doesn't need to be any user interaction (although i could do it manually and a single record at a time but that seems odd),so I want to call all the records which need the change, run a mapping script to change them, the save all of the changes without anyone else doing the same thing to the same records at that time.
Now i use a Unit of Work (i assume thats the same as the Unit of Work Pattern, since its the same as the link provided by AJ earlier), never red any documentation on it adding transactions. However if AJ's unit of work stops concurrency in the example above that would work, however is all the records in the example can't be changed by another user wouldn't that case performance issues?
Wednesday, March 21, 2018 2:38 AM -
User475983607 posted
EnenDaveyBoy
As i said previously, that example uses a simple CRUD operation which takes 1 entity, and uses try catch to catch the error of one entity and Stop the process, if I use try and catch it could end up with an endless loop of lots of people trying to update the same records and it never completing.and I am not sure how to loop throughmany records.I might just have to try some stuff and see what happens although im not sure how to test it when i get something working
You're pretty far off the mark or have other design issues that are not expressed in this post.
Wednesday, March 21, 2018 9:41 AM -
User1120430333 posted
What you have described is what i want to do, however there doesn't need to be any user interaction (although i could do it manually and a single record at a time but that seems odd),
What would be the point of concurrency checking if it were not for data persistence in a multi-user environment? The concurrency check is to prevent the last one wins data corruption.
so I want to call all the records which need the change, run a mapping script to change them, the save all of the changes without anyone else doing the same thing to the same records at that time.
This is not viable.
The logical thinking here is all the tables are treated as a group logically by your ability to program it in a logical manner here. The logic here is the record in the main table is checked on the concurrency. If the concurrency check passes, then you take the tables as a group, as a whole, for data persistence wrapping the entire group of records to be persisted to tables in a System.Transaction. Either all records in all tables in the group persist successfully or upon failure, any records that persisted before the failure are rolled back to their previous state.
However if AJ's unit of work stops concurrency in the example above that would work, however is all the records in the example can't be changed by another user wouldn't that case performance issues?
The UoW and the generic repository or the generic repository by itself may not be viable for you as design patterns. I know for me the patterns simply wouldn't even be considered. You can't go around doing table locks that would affect the performance of the application and the application's consistency either.
You have to come up with a viable solution, which would be the main table's record on the record update is concurrency checked, and if the check is passed, then all records in all tables are persisted as a single transaction, else the nothing is done no other program logic is executed to persist records in other table, which would be a program logical lock and not a physical locking of anything.
You and your program are suppose to be in charge here on how it is logically done, and not technology dictating how it's done.
I don't know whatever else you are trying to come up with, but it's most likely not viable.
Wednesday, March 21, 2018 12:25 PM -
User1034446946 posted
EnenDaveyBoy
As i said previously, that example uses a simple CRUD operation which takes 1 entity, and uses try catch to catch the error of one entity and Stop the process, if I use try and catch it could end up with an endless loop of lots of people trying to update the same records and it never completing.and I am not sure how to loop throughmany records.I might just have to try some stuff and see what happens although im not sure how to test it when i get something working
You're pretty far off the mark or have other design issues that are not expressed in this post.
My script assigns stock out, to stock in, if it happens twice it will litterly messes everything up, maybe i just don't understand the parts i can't see.
Wednesday, March 21, 2018 2:15 PM -
User475983607 posted
Sorry, am i far off the mark with the explanation of the example, or endless loop?Your first post asked for help regarding concurrency. Generally in a web app uses optimistic concurrency to guard against multiple updates. The concept is pretty simply. A disconnected copy of the record is passed to the user which includes a timestamp. If the user invokes a save, the timestamp is used as a filter for updating the record. If the result is no records are updated then a message is returned to the user letting them know that the state has changed. Usually the new record state is also returned so the user can make a decision on what to do next. This is outlined in the linked documentation in my previous post.
Anyway, this is a design pattern that you can use if it fits your needs.
My script assigns stock out, to stock in, if it happens twice it will litterly messes everything up, maybe i just don't understand the parts i can't see.This sounds like a vague design bug based on an unknown business requirement. I can only agree that optimistic concurrency will not work because you telling us directly. I have no idea though. It also sounds like the design is not completely thought out and you need to get with your team and discuss how the inventory system should flow. Basically, list out all the possible states and expected results. Document the requirements. Then come up with a design that will meet the requirements.
Inventory systems are not new and you should be able to find plenty of examples in the web. The key is building a proper db schema. IMHO, this statement seems a bit fishy, "My script assigns stock out, to stock in". Generally, this is not the case. You should have a stock in record and a stock out record. If you have a table with columns name [Stock In] and [Stock Out] then you have a design bug, IMHO.
Wednesday, March 21, 2018 3:12 PM -
User1034446946 posted
mgebhard
EnenDaveyBoy
Sorry, am i far off the mark with the explanation of the example, or endless loop?Your first post asked for help regarding concurrency. Generally in a web app uses optimistic concurrency to guard against multiple updates. The concept is pretty simply. A disconnected copy of the record is passed to the user which includes a timestamp. If the user invokes a save, the timestamp is used as a filter for updating the record. If the result is no records are updated then a message is returned to the user letting them know that the state has changed. Usually the new record state is also returned so the user can make a decision on what to do next. This is outlined in the linked documentation in my previous post.
Anyway, this is a design pattern that you can use if it fits your need
Someone in another posted suggested concurrency as a possible solution.
mgebhard
EnenDaveyBoy
My script assigns stock out, to stock in, if it happens twice it will litterly messes everything up, maybe i just don't understand the parts i can't see.This sounds like a vague design bug based on an unknown business requirement. I can only agree that optimistic concurrency will not work because you telling us directly. I have no idea though. It also sounds like the design is not completely thought out and you need to get with your team and discuss how the inventory system should flow. Basically, list out all the possible states and expected results. Document the requirements. Then come up with a design that will meet the requirements.
Inventory systems are not new and you should be able to find plenty of examples in the web. The key is building a proper db schema. IMHO, this statement seems a bit fishy, "My script assigns stock out, to stock in". Generally, this is not the case. You should have a stock in record and a stock out record. If you have a table with columns name [Stock In] and [Stock Out] then you have a design bug, IMHO.
I don'tsee how the schema is relevent, base on your two table examples, if I have a script that links the stock out to the stock in, and two people access the procedure/records at the same time to do the same thing they will double allocate, that means all stock calculations are wrong regardless of schema.
Wednesday, March 21, 2018 9:21 PM -
User475983607 posted
I don'tsee how the schema is relevent, base on your two table examples, if I have a script that links the stock out to the stock in, and two people access the procedure/records at the same time to do the same thing they will double allocate, that means all stock calculations are wrong regardless of schema.The database schema drives everything. I'm taken back that you would say such foolishness in an open forum.
Seriously though you need to solidify your requirements and present the requirements in a clear form. Then maybe someone can provide guidance. From my perspective the inventory system has been solved long ago so I'm not sure what problem you are trying to solve exactly. Stuff comes in and stuff goes out in the form of electronic records. If you have a situation where two users are looking at the same record and that record contain the inventory totals you have a schema bug and need to rethink the design.
Wednesday, March 21, 2018 9:41 PM -
User1034446946 posted
After looking into Transaction further i think Transaction would will do what I want, as it offers pessimistic concurrency.
Thanks for the help
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, March 22, 2018 1:48 AM