FIM 2010: How to keep previous attribute value(s) in Metaverse
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)). http://idarchitect.net/wp-content/uploads/2015/01/managerIDHistory_MV.png
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.