Geeks With Blogs
Patrice Calve Life's short, have fun

Last year, I was working on a CAB/SCSF project that had to deal with concurrency (when a user tries to save changed data, but data on the server was already changed by someone else). 

We used optimistic concurrency and tried to auto-resolve the issues whenever possible and where the business rules allowed it.  Whenever auto-merge was not possible, we had to inform the user and provide a mechanism to allow the user to first discover the conflicts and choose the best answer.

Anyway, we had to deal with 3 information:

  1. The values changed by the user
  2. The original values
  3. The latest server values

On the client side, we kept 1 and 2 in separate variables:

Customer _customer;
Customer _customer_original;

Something trivial. 

However, I didn't like the fact that for each class, the original/updated state handling had to be handled by objects outside the class's scope (basic rule of thumbs).

The project was canned and never had the chance to work on a solution, until now...

I created a generic Historical<T> class that any business entity class could inherit. 

using System;
using System.Collections.Generic;
using System.Text;

namespace ClassLibrary1
{
   public class Historical<T>
   {
      /// <summary>
      /// Lorem Ipsum about the Original Value
      /// </summary>
      private T _original = default(T);
      private bool _initializing = true;
      private object lockObject = new object();
      internal bool Initializing
      {
         get { return _initializing; }
         set 
         {
            lock (lockObject)
            {
               _initializing =
value;
               if (_initializing == false)
                  makeACopy();
            }
         }
      }

      private void makeACopy()
      {
         if (_original == null)
            if (!_initializing)
               _original = (T)
this.MemberwiseClone();
      }

      public Historical()
      {
         _original =
default(T);
      }

      public T OriginalValues
      {
         get { return _original; }
      }

   }
}

Now, for the Business Entity Class, all I have to do is to inherit from this Historical class: 

public class Class1 : Historical<Class1>
{
   private string _name = "Not Set";

   public string Name
   {
      get { return _name; }
      set {_name = value; }
   }
}

I was presently supprised to see that it was possible (in C#) to declare a class "Class1" that inherits from a generic class "Historical" that referenced the child class!  Kind of a chicken and egg mystery broken !

Now, let's go back to the Historical<T> class, notice how the bool Initialized property is Internal.  This means that to benefit from the OriginalValues can only be given if the Initializing is set to false by an internal class.  This fits well in the CAB world where the Business Entity Classes are "pictures" of data on a server;  A piece of code needs to fetch the data from the server, create the Business Entity Class and fill in the values.

Here's an example of the data store class:

using System;
using System.Collections.Generic;
using System.Text;

namespace ClassLibrary1
{
   public static class
Store
   {
      public static Class1 GetClass1(int id)
      {
       
         //Get data from server and then set the values...

         Class1 c = new Class1();
         c.Name = "Pat";
         c.DateOfBirth = new DateTime(2000, 1, 2);

         //We're done with setting the values...
         c.Initializing = false;

         return c;
       }
   }
}

So, for a "client dev" point of view, the Class1 is very simple and easy to work with, allows modification to the data, while keeping track of the original values.  This "store" is a bad example

And quite frankly, we could go a step further and actually make the class1 partial, create a second "partial" class that inherits the Historical<T>.  This would make the original class1 "code generator friendly".

This strategy is CAB/SCSF friendly because:

  • The Business Entity class is easy to use from the GUI (add/update)
  • Adds benefits for handling concurrency
  • Non-intrusive

Wadaya think?

Pat 

Posted on Thursday, March 8, 2007 2:55 PM P&P Software Factories | Back to top


Comments on this post: Providing historical information to classes

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Patrice CalvĂ© | Powered by: GeeksWithBlogs.net