locked
I have a repository that looks like this RRS feed

  • 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

    Thanks for the info, my Generic Repository has grown a little more than normal to accomodate things like count andother bits and pieces and to add a concurrency method isn't an issue either tbh, I know at some point I will have to move away from it but at present I have other things to get working first, but it is on the to do list.

    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

    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

    With regards, Angelina Jolie

    Thanks i already use a Unit of Work, but that doesn't solve the concurrency issue, and I want my records to update the ones without a concurrecy issue and ignore the ones with.

    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.

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

    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? :)

    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.

    Wednesday, March 21, 2018 12:31 AM
  • User1034446946 posted

    The MS docs explain how to handle concurrency.

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

    Most likely your design will need a little refactoring to add this feature.

    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

    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.

    I am getting a little confused.

    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.

    Sorry, am i far off the mark with the explanation of the example, or endless loop?

    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