Using the ValueMerging event of an ObjectReader

In a previous post on concurency error handling in ObjectSpaces I spoke of the three versions that an object has: the current in-memory representation, the original values of the properties during the time of materialization and the persistent values, being the values stored in the database.

It became clear to me that I hadn’t explained the purpose of the original values very well. What I should have added was the remark that the original values are used to build the WHERE clause of the UPDATE or DELETE statement. The properties of the object that are marked as UseForConcurrency=”true” will be used in this clause. If there are no records affected in the UPDATE or DELETE statement, an SqlException is thrown by ADO.NET. This exception is caught by the OS layer and a PersistenceException is thrown instead.

There is something you can do instead of doing a Resync on your object. It has to do with the ValueMerging event of the ObjectReader. Here’s a bit of background:

Whenever an object is materialized by OS, a check is made if the object is tracked already by the context corresponding to the object that does the retrieval. If this is the case you will get the same reference as the object that was retrieved previously. This way there will only be one object, instead of two or more from every additional retrieval. If the database values have changed, you will not notice this by default. The object does not get the new values. The current and original values remain unchanged. But there is a way to influence these values during retrieval and merge the persistent values with either the current or original values.

For this you will have to retrieve the object(s) the second or any consecutive times by using an ObjectReader. Here you get a chance to hook up an eventhandler during the moment that an object is materialized again. The event is called ValueMerging. Here’s how you add an eventhandler to that event:

publicvoid ValueMergingDemo()
{
  SqlConnection con =
new SqlConnection(
      ConfigurationSettings.ConnectionStrings[“ObjectSpaces”]);
  ObjectSpace os =
new ObjectSpace(
      ConfigurationSettings.AppSettings[“MappingSchema”], con);

  // Retrieve object for first time and change some property
  Author p = (Author)os.GetObject(
typeof(Author),
      “AuthorID=’172-32-1176′”);
  p.FirstName = “Alex”;

  // Retrieve same object again, but with an ObjectReader
  ObjectReader reader = os.GetObjectReader(typeof(Author),
      “AuthorID=’172-32-1176′”);

  // Hook up event handler to ValueMerging
  reader.ValueMerging += new ValueRecordMergeEventHandler
      (ValueMergingHandler);

Again, you need the ObjectReader. Although the ObjectReader is used internally by the GetObject and GetObjectSet methods, these will not cut it, as you cannot get at the ObjectReader object.

The delegate of type ValueRecordMergeEventHandler is defined as

public delegate void ValueRecordMergeEventHandler(object sender,
    ValueRecordMergeEventArgs e)

The ValueMergingHandler method is shown later. As the registered eventhandler method it is called by OS once the ValueMerging event fires. This happens automatically when you retrieve the object(s) again. The sample will show the current values from the actual properties of the object and the original values from the original ValueRecord.

  if (reader.HasObjects)
  {
    // This will trigger eventhandler
    reader.Read();
    p = (Author)reader.Current;
    ObjectContext ctx = ObjectContext.GetInternalContext(os);
    Console.WriteLine(“Original: ” +
        ctx.GetOriginalValueRecord(p)[“FirstName”].ToString());
    Console.WriteLine(“Current: ” + p.FirstName);
  }
}

Now for the cool stuff. Normally changing the current ValueRecord has no effect as they are copies of the actual values stored inside the ObjectContext and not the actual properties. They are not written back to the object. Except during the ValueMerging event. The ValueRecordMergeEventArgs object offers three properties called Current-, Original- and PersistentValueRecord. This makes it the ideal moment to change the values of the object’s properties based upon these three versions. The changes you make to the current ValueRecord are transferred to the object. Pretty nifty, huh? Any changes to the original ValueRecord are maintained and (obviously) changes to the persistent ValueRecord make no sense here, because no values are being stored to the database.

This is a sample of what you could do during the ValueMerging event: change the current and original values to something stupid. Or something more intelligent, but I will leave that up to you.

privatevoid ValueMergingHandler(object sender,
    ValueRecordMergeEventArgs e)
{
  // This event occurs for every object that is materialized again.
  try
  {
    // All three versions of the object values are available
    Console.WriteLine(e.CurrentValueRecord[“FirstName”]);
    Console.WriteLine(e.OriginalValueRecord[“FirstName”]);
    Console.WriteLine(e.PersistentValueRecord[“FirstName”]);
    // Change current and original values
    e.CurrentValueRecord[“FirstName”] = “Current FirstName from ValueMerging event”;
    e.OriginalValueRecord[“FirstName”] = “Original FirstName from ValueMerging event”;
  }
  catch (Exception) { }
}

Be aware that the same eventhandler is used for all objects that are retrieved a second time. This means it is also called for any subobjects that materialize because of a span.

Lastly, when would you use the ValueMerging event? Well, you could use it in:

  • an alternative approach for Resync during concurrency error handling. The real challenge here is that you would need to use a correct OPath expression to retrieve exactly the objects that had concurrency errors. If you need to interact with the user through the UI, it cannot be used in all circumstances such as ASP.NET.
  • a selective refresh on objects. I can’t think of a particular usage scenario, but just imagine what you could do during the refresh based upon all three versions of the property values.

 

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s