Sometimes we need the previous value of an attribute. For example we may need id of a user's previous manager or the name of a user's previous department.  We can imagine a lot of scenarios where it may be useful to know the last value of attribute. When you are building solution using FIM Portal you can quite easily react on attribute updates and prepare workflows which will use/keep previous value of some attribute.  This is a tricky requirement to fulfill using just FIM Synchronization. Information about the previous value of attribute is available for only a very short time. You can of course pass it to other flows using transaction properties but it will be only available during the synchronization cycle as an attribute is updated. This information is lost after this completes.

Solution

The trick is to keep both values together in some dedicated MV attribute. For example let's say we already have managerID attribute and we want previous value(s) of the attribute in managerIDHistory. The we will have following values in Metaverse.

 

Attribute Value
managerID 1234
managerIDHistory 1234;

When we change managers ID to 5678 situation will look like this:

 

Attribute Value
managerID 5678
managerIDHistory 5678;1234;

We can of course keep as well older values (whole history). However you have to be careful in that case about size of your attribute and frequency of changes. In case you will keep older values as well this is how it can look after next update:

Attribute Value
managerID 1111
managerIDHistory 1111;5678;1234;

In any case if you split the list stored in managerIDHistory attribute on first position you have current value of managerID attribute, on second previous value, and so on .

case "cd.person:managerID->mv.nbpPerson:managerIDHistory":
{
   if (csentry["managerID"].IsPresent)
   {
    if (!mventry["managerIDHistory"].IsPresent)
       mventry["managerIDHistory"].StringValue = "";
         if (!mventry["managerIDHistory"].StringValue.StartsWith(csentry["managerID"].StringValue + ";"))       mventry"managerIDHistory"].StringValue = csentry["managerID"].StringValue + ";" + mventry["managerIDHistory"].StringValue;   }
} break;

Metaverse attribute type

What MV attribute type to use? In most cases you can expect that this attribute will grow a little after some time, so you will need some space. Indexed strings are limited to 448 characters which may be to short. Non-indexable string would be best choice in that case (it is stored in SQL as nvarchar(MAX)). managerIDHistory attribute definition

Import flow example

In the import flow you just add the current value of the attribute in the first position (in case it is not yet added there). Here is an example of the code for an advanced import flow rule:

Export flow example

Any of your export attribute flows can make use of the previous values of the attribute. First you have to read the value list with the code similar to following example:

if (mventry["managerIDHistory"].IsPresent &&
     (mventry["managerIDHistory"].StringValue.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Length > 1) ) {
   string[] hist = mventry["managerIDHistory"].StringValue.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);   if (hist.Length > 0)
   {
    // use current value stored in hist[0]
  }
  if (hist.Length > 1)
  {
    // use previous value stored in hist[1]
  }
}

Then you can do whatever you want with it.

Summary

Sometimes it is useful to have the previous value of an attribute. You can easily achieve it within FIM Synchronization. The above method is good for small attributes. It is useful in case you need this value during synchronization.

Extending solution - you can extend data format and keep more information, for example date and time of the attribute change. Note that this method does not cover  full history reporting.

 

Source Reference

The article has originally been published by the author on IDArchitect.NET blog.