Optimistic concurrency control in a WCF service

6 posts, 1 answers
  1. Henning
    Henning avatar
    6 posts
    Member since:
    Sep 2011

    Posted 07 Oct 2011 Link to this post

    Hello,

    I'm trying to use OpenAccess in a WCF service. I followed the "SofiaCarRental" Sample that's avaible in the OpenAccess SDK.
    Atm I have only a limited project for testing concurrency. And that's where the problems start.

    My WCF Contract has 2 methods:

    -Customer GetCustumer(int i_customer)
    -void UpdateCustomer(Customer newCustomer)

    I've wrote a simple console client to test concurrency:

            static void Main(string[] args)
            {
                Service1Client client = new Service1Client();

                Customer c = client.GetCustomer(107193);
                Customer c2 = client.GetCustomer(107193);

                c.Firstname = "blaaaaaaaaaaaaaaa";
                client.UpdateCustomer(c);

                c2.Lastname = "bluuuuuuubbbbbbbb";
                client.UpdateCustomer(c2);

                Console.WriteLine("Done!");
                Console.ReadLine();
            }

    As you can see it gets the same Customer 2 times and changes the "firstname" field of the first copy and the "lastname" field of the 2nd copy. Both copies are send to the service to be updated.

    This is how the service looks like:
    public class Service1 : IService1
        {
            public Customer GetCustomer(int i_customer)
            {
                CustomerModel customerModel = new CustomerModel();
     
                var query = from cust in customerModel.Customers
                            where cust.I_customer == i_customer
                            select cust;
     
                Customer customer = query.First();
                return customer;
            }
     
            public void UpdateCustomer(Customer newCustomer)
            {
                CustomerModel customerModel = new CustomerModel();
     
                var query = from cust in customerModel.Customers
                            where cust.I_customer == newCustomer.I_customer
                            select cust;
     
                Customer oldCustomer = query.FirstOrDefault();
     
                PropertyInfo[] newCust = newCustomer.GetType().GetProperties();
     
                foreach (PropertyInfo prop in newCust)
                {
                    if (prop.GetValue(oldCustomer, null) == null || prop.GetValue(oldCustomer, null).Equals(prop.GetValue(newCustomer, null)))
                        continue;
                     
                    prop.SetValue(oldCustomer, prop.GetValue(newCustomer, null), null);
                }
     
                customerModel.SaveChanges();
            }
        }

    The UpdateCustomer Method gets the Customer again from the database then updates all the field of that instance with the ones of the Method parameter if they have been changed. This is just like in the "SofiaCarRental" Sample.

    However, no optimistic concurrency mode is working with this approach.
    When I use timestamp, OpenAccess doesn't use the timestamp field from "newCustomer". My only guess is it uses an internal field somewhere that is set when getting "oldCustomer".

    When I use "Changed" as concurrency mode, the second update overwrites the first one, setting the "firstname" field back to it's original value.

    How can I solve this problem?
    Thanks for any help you can give me!
  2. Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 12 Oct 2011 Link to this post

    Hello Henning,

     Optimistic concurrency control is automatically handled with OpenAccess only in the case where an objects is obtained and than updated by the same context since the context is basically the object that keeps track of the old/new values. This however is a scenario that is usually met in a desktop application where one context is created per thread and manages all of the CRUD operations in that thread.

    This however is not applicable for multithreading and stateless scenarios like WCF or ASP.NET. With these application architectures you are creating a context on each request for reading an object and then another one to update the edited object in the database. 

    In ASP .NET scenarios there is an approach with storing the original state of the object in the Session and then on update to do a comparison between the old and the current values in the database prior to updating.

    That of course is not possible in WCF as there is no such state-management mechanism in a service. At the moment this is exactly a problem that we are addressing and our best-practices solution will be DTO objects that will be automatically generated by a template in our product. The DTO objects will transfer the original state of the object serialized through the wire. After update operation has been performed on the client side, the original state will be deserialized on the service side and checked for concurrency control issues before the update operation is performed.

    These DTO templates will be part of our product for the following Q3 2011 release that will be public in the middle of November. In the meantime, I will re-post in this forum thread with a beta-version of these templates so you might test them beforehand if you would like to. I will present you the first version of the templates in about two weeks time.

    Thanks a lot for your understanding.

    Kind regards,
    Zoran
    the Telerik team

    Check out the latest stable build of Telerik OpenAccess ORM. Download it and benefit from our new Project Templates.

  3. DevCraft banner
  4. Henning
    Henning avatar
    6 posts
    Member since:
    Sep 2011

    Posted 26 Oct 2011 Link to this post

    Hello,

    It's good to hear that this will be implemented in the upcomming version.
    I'd love to try the beta version you offered.

    Thanks for your reply.
  5. Henning
    Henning avatar
    6 posts
    Member since:
    Sep 2011

    Posted 17 Nov 2011 Link to this post

    Hello,

    with the new Q3 release I've now retested this, but I'm still unable to get it to work. I use the build in code generation from the domain model so it generates the following files:

    Assembler.cs
    Converter.cs
    DynamicLinq.cs
    Repositories.cs
    Service.cs
    Transport.cs

    and of course the WCF service itself with all the CRUD operations.
    However, I'm still unable to get optimistic concurrency control. Do I have to enable it somehow? If so, how?
    Which concurrency mode do I have to set in the database?

    When I try my client (that still looks pretty much the same as in my first post), the second call to UpdateCustomer still overwrites the changes made in the first one.

    I'd be really grateful if you could tell me how to get the optimistic concurrency control to work.
  6. Answer
    Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 22 Nov 2011 Link to this post

    Hello Henning,

     The behavior you observe is due to the fact that the services are generated so that they do not transport version information for the objects by default. This is easy to be manually changed if you open the Converters.cs file and look into the Create() method of the KeyUtility class. The Create() method looks like this at the moment:

    public virtual ObjectKey Create(object entity)
    {
          return ObjectKey.Create(entity);
          // If need to pass versioning information back and forth
           // you can use the following method to create an ObjectKey.
           //return ObjectKey.CreateWithVersion(entity);
    }

    As the comment states, you should just change the method to use the following implementation:

    public virtual ObjectKey Create(object entity)
    {
           return ObjectKey.Create(entity);
    }

    Regards,
    Zoran
    the Telerik team

    NEW and UPDATED OpenAccess ORM Resources. Check them out!

  7. Henning
    Henning avatar
    6 posts
    Member since:
    Sep 2011

    Posted 23 Nov 2011 Link to this post

    Hello,

    Awesome! It now works fine! Thanks alot!
Back to Top
DevCraft banner